Bug 1935611 - Fix libyuv/libpng link failed for loongarch64. r=glandium,tnikkel,ng
[gecko.git] / security / manager / ssl / NSSKeyStore.cpp
blob56d024032cbde6266ed856b95ea162b7c2527d67
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 "ScopedNSSTypes.h"
10 #include "mozilla/AbstractThread.h"
11 #include "mozilla/Base64.h"
12 #include "mozilla/Logging.h"
13 #include "mozilla/SyncRunnable.h"
14 #include "nsIThread.h"
15 #include "nsNSSComponent.h"
16 #include "nsPK11TokenDB.h"
17 #include "nsXULAppAPI.h"
19 /* Implementing OSKeyStore when there is no platform specific one.
20 * This key store instead puts the keys into the NSS DB.
23 using namespace mozilla;
24 using mozilla::SyncRunnable;
26 LazyLogModule gNSSKeyStoreLog("nsskeystore");
28 NSSKeyStore::NSSKeyStore() {
29 MOZ_ASSERT(XRE_IsParentProcess());
30 if (!XRE_IsParentProcess()) {
31 // This shouldn't happen as this is only initialised when creating the
32 // OSKeyStore, which is ParentProcessOnly.
33 return;
35 Unused << EnsureNSSInitializedChromeOrContent();
36 Unused << InitToken();
38 NSSKeyStore::~NSSKeyStore() = default;
40 nsresult NSSKeyStore::InitToken() {
41 if (!mSlot) {
42 mSlot = UniquePK11SlotInfo(PK11_GetInternalKeySlot());
43 if (!mSlot) {
44 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug,
45 ("Error getting internal key slot"));
46 return NS_ERROR_NOT_AVAILABLE;
49 return NS_OK;
52 nsresult NSSKeyStore::StoreSecret(const nsACString& aSecret,
53 const nsACString& aLabel) {
54 NS_ENSURE_STATE(mSlot);
56 // It is possible for multiple keys to have the same nickname in NSS. To
57 // prevent the problem of not knowing which key to use in the future, simply
58 // delete all keys with this nickname before storing a new one.
59 nsresult rv = DeleteSecret(aLabel);
60 if (NS_FAILED(rv)) {
61 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug,
62 ("DeleteSecret before StoreSecret failed"));
63 return rv;
66 uint8_t* p = BitwiseCast<uint8_t*, const char*>(aSecret.BeginReading());
67 UniqueSECItem key(SECITEM_AllocItem(nullptr, nullptr, aSecret.Length()));
68 if (!key) {
69 return NS_ERROR_OUT_OF_MEMORY;
71 key->type = siBuffer;
72 memcpy(key->data, p, aSecret.Length());
73 key->len = aSecret.Length();
74 UniquePK11SymKey symKey(
75 PK11_ImportSymKey(mSlot.get(), CKM_AES_GCM, PK11_OriginUnwrap,
76 CKA_DECRYPT | CKA_ENCRYPT, key.get(), nullptr));
77 if (!symKey) {
78 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error creating NSS SymKey"));
79 return NS_ERROR_FAILURE;
81 UniquePK11SymKey storedKey(
82 PK11_ConvertSessionSymKeyToTokenSymKey(symKey.get(), nullptr));
83 if (!storedKey) {
84 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug,
85 ("Error storing NSS SymKey in DB"));
86 return NS_ERROR_FAILURE;
88 SECStatus srv =
89 PK11_SetSymKeyNickname(storedKey.get(), PromiseFlatCString(aLabel).get());
90 if (srv != SECSuccess) {
91 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error naming NSS SymKey"));
92 (void)PK11_DeleteTokenSymKey(storedKey.get());
93 return NS_ERROR_FAILURE;
96 return NS_OK;
99 nsresult NSSKeyStore::DeleteSecret(const nsACString& aLabel) {
100 NS_ENSURE_STATE(mSlot);
102 UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
103 mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
104 nullptr));
105 if (!symKey) {
106 // Couldn't find the key or something is wrong. Be nice.
107 return NS_OK;
109 for (PK11SymKey* tmp = symKey.get(); tmp; tmp = PK11_GetNextSymKey(tmp)) {
110 SECStatus srv = PK11_DeleteTokenSymKey(tmp);
111 if (srv != SECSuccess) {
112 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error deleting NSS SymKey"));
113 return NS_ERROR_FAILURE;
116 return NS_OK;
119 bool NSSKeyStore::SecretAvailable(const nsACString& aLabel) {
120 if (!mSlot) {
121 return false;
124 UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
125 mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
126 nullptr));
127 if (!symKey) {
128 return false;
130 return true;
133 nsresult NSSKeyStore::EncryptDecrypt(const nsACString& aLabel,
134 const std::vector<uint8_t>& inBytes,
135 std::vector<uint8_t>& outBytes,
136 bool encrypt) {
137 NS_ENSURE_STATE(mSlot);
139 UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
140 mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
141 nullptr));
142 if (!symKey) {
143 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug,
144 ("Error finding key for given label"));
145 return NS_ERROR_FAILURE;
147 return DoCipher(symKey, inBytes, outBytes, encrypt);
150 nsresult NSSKeyStore::RetrieveSecret(const nsACString& aLabel,
151 /* out */ nsACString& aSecret) {
152 NS_ENSURE_STATE(mSlot);
154 UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
155 mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
156 nullptr));
157 if (!symKey) {
158 MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug,
159 ("Error finding key for given label"));
160 return NS_ERROR_FAILURE;
163 // Unfortunately we can't use PK11_ExtractKeyValue(symKey.get()) here because
164 // softoken marks all token objects of type CKO_SECRET_KEY as sensitive. So
165 // we have to wrap and unwrap symKey to obtain a non-sensitive copy of symKey
166 // as a session object.
168 const CK_MECHANISM_TYPE mechanism = CKM_AES_KEY_WRAP_KWP;
170 UniquePK11SymKey wrappingKey(
171 PK11_KeyGen(mSlot.get(), CKM_AES_KEY_GEN, nullptr, 16, nullptr));
172 if (!wrappingKey) {
173 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
176 SECItem wrapLen = {siBuffer, nullptr, 0};
177 nsresult rv = MapSECStatus(PK11_WrapSymKey(
178 mechanism, nullptr, wrappingKey.get(), symKey.get(), &wrapLen));
179 NS_ENSURE_SUCCESS(rv, rv);
181 if (wrapLen.len > INT_MAX - 8) { /* PK11_UnwrapSymKey takes an int keySize */
182 return NS_ERROR_FAILURE;
185 // Allocate an extra 8 bytes for CKM_AES_KEY_WRAP_KWP overhead.
186 UniqueSECItem wrappedKey(
187 SECITEM_AllocItem(nullptr, nullptr, wrapLen.len + 8));
188 if (!wrappedKey) {
189 return NS_ERROR_FAILURE;
192 rv = MapSECStatus(PK11_WrapSymKey(mechanism, nullptr, wrappingKey.get(),
193 symKey.get(), wrappedKey.get()));
194 NS_ENSURE_SUCCESS(rv, rv);
196 UniquePK11SymKey unwrappedKey(PK11_UnwrapSymKey(
197 wrappingKey.get(), mechanism, nullptr, wrappedKey.get(), CKM_AES_GCM,
198 CKA_DECRYPT, static_cast<int>(wrapLen.len)));
199 if (!unwrappedKey) {
200 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
203 rv = MapSECStatus(PK11_ExtractKeyValue(unwrappedKey.get()));
204 NS_ENSURE_SUCCESS(rv, rv);
206 const SECItem* keyData = PK11_GetKeyData(unwrappedKey.get()); /* weak ref */
207 if (!keyData) {
208 return NS_ERROR_FAILURE;
211 aSecret.Assign(reinterpret_cast<char*>(keyData->data), keyData->len);
212 return NS_OK;