Backed out changeset f53842753805 (bug 1804872) for causing reftest failures on 15535...
[gecko.git] / security / manager / ssl / NSSKeyStore.cpp
blob2850a135654bc3c16684aa284429196311ecbde9
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
7 #include "NSSKeyStore.h"
9 #include "mozilla/AbstractThread.h"
10 #include "mozilla/Base64.h"
11 #include "mozilla/Logging.h"
12 #include "mozilla/SyncRunnable.h"
13 #include "nsIThread.h"
14 #include "nsNSSComponent.h"
15 #include "nsPK11TokenDB.h"
16 #include "nsXULAppAPI.h"
18 /* Implementing OSKeyStore when there is no platform specific one.
19 * This key store instead puts the keys into the NSS DB.
22 using namespace mozilla;
23 using mozilla::SyncRunnable;
25 LazyLogModule gNSSKeyStoreLog("nsskeystore");
27 NSSKeyStore::NSSKeyStore() {
28 MOZ_ASSERT(XRE_IsParentProcess());
29 if (!XRE_IsParentProcess()) {
30 // This shouldn't happen as this is only initialised when creating the
31 // OSKeyStore, which is ParentProcessOnly.
32 return;
34 Unused << EnsureNSSInitializedChromeOrContent();
35 Unused << InitToken();
37 NSSKeyStore::~NSSKeyStore() = default;
39 nsresult NSSKeyStore::InitToken() {
40 if (!mSlot) {
41 mSlot = UniquePK11SlotInfo(PK11_GetInternalKeySlot());
42 if (!mSlot) {
43 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug,
44 ("Error getting internal key slot"));
45 return NS_ERROR_NOT_AVAILABLE;
48 return NS_OK;
51 nsresult NSSKeyStoreMainThreadLock(PK11SlotInfo* aSlot) {
52 nsCOMPtr<nsIPK11Token> token = new nsPK11Token(aSlot);
53 return token->LogoutSimple();
56 nsresult NSSKeyStore::Lock() {
57 NS_ENSURE_STATE(mSlot);
59 if (!NS_IsMainThread()) {
60 nsCOMPtr<nsIThread> mainThread;
61 nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
62 if (NS_FAILED(rv)) {
63 return NS_ERROR_FAILURE;
66 // Forward to the main thread synchronously.
67 SyncRunnable::DispatchToThread(
68 mainThread, NS_NewRunnableFunction("NSSKeyStoreMainThreadLock",
69 [slot = mSlot.get()]() {
70 NSSKeyStoreMainThreadLock(slot);
71 }));
73 return NS_OK;
76 return NSSKeyStoreMainThreadLock(mSlot.get());
79 nsresult NSSKeyStoreMainThreadUnlock(PK11SlotInfo* aSlot) {
80 nsCOMPtr<nsIPK11Token> token = new nsPK11Token(aSlot);
81 return NS_FAILED(token->Login(false /* force */)) ? NS_ERROR_FAILURE : NS_OK;
84 nsresult NSSKeyStore::Unlock() {
85 NS_ENSURE_STATE(mSlot);
87 if (!NS_IsMainThread()) {
88 nsCOMPtr<nsIThread> mainThread;
89 nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
90 if (NS_FAILED(rv)) {
91 return NS_ERROR_FAILURE;
94 // Forward to the main thread synchronously.
95 nsresult result = NS_ERROR_FAILURE;
96 SyncRunnable::DispatchToThread(
97 mainThread,
98 NS_NewRunnableFunction("NSSKeyStoreMainThreadUnlock",
99 [slot = mSlot.get(), result = &result]() {
100 *result = NSSKeyStoreMainThreadUnlock(slot);
101 }));
103 return result;
106 return NSSKeyStoreMainThreadUnlock(mSlot.get());
109 nsresult NSSKeyStore::StoreSecret(const nsACString& aSecret,
110 const nsACString& aLabel) {
111 NS_ENSURE_STATE(mSlot);
112 if (NS_FAILED(Unlock())) {
113 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
114 return NS_ERROR_FAILURE;
117 // It is possible for multiple keys to have the same nickname in NSS. To
118 // prevent the problem of not knowing which key to use in the future, simply
119 // delete all keys with this nickname before storing a new one.
120 nsresult rv = DeleteSecret(aLabel);
121 if (NS_FAILED(rv)) {
122 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug,
123 ("DeleteSecret before StoreSecret failed"));
124 return rv;
127 uint8_t* p = BitwiseCast<uint8_t*, const char*>(aSecret.BeginReading());
128 UniqueSECItem key(SECITEM_AllocItem(nullptr, nullptr, aSecret.Length()));
129 if (!key) {
130 return NS_ERROR_OUT_OF_MEMORY;
132 key->type = siBuffer;
133 memcpy(key->data, p, aSecret.Length());
134 key->len = aSecret.Length();
135 UniquePK11SymKey symKey(
136 PK11_ImportSymKey(mSlot.get(), CKM_AES_GCM, PK11_OriginUnwrap,
137 CKA_DECRYPT | CKA_ENCRYPT, key.get(), nullptr));
138 if (!symKey) {
139 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error creating NSS SymKey"));
140 return NS_ERROR_FAILURE;
142 UniquePK11SymKey storedKey(
143 PK11_ConvertSessionSymKeyToTokenSymKey(symKey.get(), nullptr));
144 if (!storedKey) {
145 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug,
146 ("Error storing NSS SymKey in DB"));
147 return NS_ERROR_FAILURE;
149 SECStatus srv =
150 PK11_SetSymKeyNickname(storedKey.get(), PromiseFlatCString(aLabel).get());
151 if (srv != SECSuccess) {
152 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error naming NSS SymKey"));
153 (void)PK11_DeleteTokenSymKey(storedKey.get());
154 return NS_ERROR_FAILURE;
157 return NS_OK;
160 nsresult NSSKeyStore::DeleteSecret(const nsACString& aLabel) {
161 NS_ENSURE_STATE(mSlot);
162 if (NS_FAILED(Unlock())) {
163 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
164 return NS_ERROR_FAILURE;
167 UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
168 mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
169 nullptr));
170 if (!symKey) {
171 // Couldn't find the key or something is wrong. Be nice.
172 return NS_OK;
174 for (PK11SymKey* tmp = symKey.get(); tmp; tmp = PK11_GetNextSymKey(tmp)) {
175 SECStatus srv = PK11_DeleteTokenSymKey(tmp);
176 if (srv != SECSuccess) {
177 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error deleting NSS SymKey"));
178 return NS_ERROR_FAILURE;
181 return NS_OK;
184 bool NSSKeyStore::SecretAvailable(const nsACString& aLabel) {
185 if (!mSlot) {
186 return false;
188 if (NS_FAILED(Unlock())) {
189 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
190 return false;
193 UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
194 mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
195 nullptr));
196 if (!symKey) {
197 return false;
199 return true;
202 nsresult NSSKeyStore::EncryptDecrypt(const nsACString& aLabel,
203 const std::vector<uint8_t>& inBytes,
204 std::vector<uint8_t>& outBytes,
205 bool encrypt) {
206 NS_ENSURE_STATE(mSlot);
207 if (NS_FAILED(Unlock())) {
208 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
209 return NS_ERROR_FAILURE;
212 UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
213 mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
214 nullptr));
215 if (!symKey) {
216 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug,
217 ("Error finding key for given label"));
218 return NS_ERROR_FAILURE;
220 return DoCipher(symKey, inBytes, outBytes, encrypt);
223 // Because NSSKeyStore overrides AbstractOSKeyStore's EncryptDecrypt and
224 // SecretAvailable functions, this isn't necessary.
225 nsresult NSSKeyStore::RetrieveSecret(const nsACString& aLabel,
226 /* out */ nsACString& aSecret) {
227 return NS_ERROR_NOT_IMPLEMENTED;