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.
34 Unused
<< EnsureNSSInitializedChromeOrContent();
35 Unused
<< InitToken();
37 NSSKeyStore::~NSSKeyStore() = default;
39 nsresult
NSSKeyStore::InitToken() {
41 mSlot
= UniquePK11SlotInfo(PK11_GetInternalKeySlot());
43 MOZ_LOG(gNSSKeyStoreLog
, LogLevel::Debug
,
44 ("Error getting internal key slot"));
45 return NS_ERROR_NOT_AVAILABLE
;
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
));
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
);
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
));
91 return NS_ERROR_FAILURE
;
94 // Forward to the main thread synchronously.
95 nsresult result
= NS_ERROR_FAILURE
;
96 SyncRunnable::DispatchToThread(
98 NS_NewRunnableFunction("NSSKeyStoreMainThreadUnlock",
99 [slot
= mSlot
.get(), result
= &result
]() {
100 *result
= NSSKeyStoreMainThreadUnlock(slot
);
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
);
122 MOZ_LOG(gNSSKeyStoreLog
, LogLevel::Debug
,
123 ("DeleteSecret before StoreSecret failed"));
127 uint8_t* p
= BitwiseCast
<uint8_t*, const char*>(aSecret
.BeginReading());
128 UniqueSECItem
key(SECITEM_AllocItem(nullptr, nullptr, aSecret
.Length()));
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));
139 MOZ_LOG(gNSSKeyStoreLog
, LogLevel::Debug
, ("Error creating NSS SymKey"));
140 return NS_ERROR_FAILURE
;
142 UniquePK11SymKey
storedKey(
143 PK11_ConvertSessionSymKeyToTokenSymKey(symKey
.get(), nullptr));
145 MOZ_LOG(gNSSKeyStoreLog
, LogLevel::Debug
,
146 ("Error storing NSS SymKey in DB"));
147 return NS_ERROR_FAILURE
;
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
;
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()),
171 // Couldn't find the key or something is wrong. Be nice.
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
;
184 bool NSSKeyStore::SecretAvailable(const nsACString
& aLabel
) {
188 if (NS_FAILED(Unlock())) {
189 MOZ_LOG(gNSSKeyStoreLog
, LogLevel::Debug
, ("Error unlocking NSS key db"));
193 UniquePK11SymKey
symKey(PK11_ListFixedKeysInSlot(
194 mSlot
.get(), const_cast<char*>(PromiseFlatCString(aLabel
).get()),
202 nsresult
NSSKeyStore::EncryptDecrypt(const nsACString
& aLabel
,
203 const std::vector
<uint8_t>& inBytes
,
204 std::vector
<uint8_t>& outBytes
,
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()),
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
;