Backed out 2 changesets (bug 1712837) for causing an increase in crashes (bug 1735798). a=backout

Backed out changeset 51773d1ab7b5 (bug 1712837)
Backed out changeset 97b0a77e4ce7 (bug 1712837)
This commit is contained in:
Cosmin Sabou 2021-12-15 12:24:03 +02:00
Родитель 667224045f
Коммит 045a43b2c8
42 изменённых файлов: 302 добавлений и 2302 удалений

11
Cargo.lock сгенерированный
Просмотреть файл

@ -2449,17 +2449,6 @@ dependencies = [
"libc",
]
[[package]]
name = "ipcclientcerts-static"
version = "0.1.0"
dependencies = [
"byteorder",
"once_cell",
"pkcs11",
"rsclientcerts",
"sha2",
]
[[package]]
name = "itertools"
version = "0.8.2"

Просмотреть файл

@ -9,7 +9,6 @@ members = [
"js/src/rust",
"js/src/wasm/cranelift",
"netwerk/test/http3server",
"security/manager/ssl/ipcclientcerts",
"security/manager/ssl/osclientcerts",
"testing/geckodriver",
"toolkit/crashreporter/rust_minidump_writer_linux",

Просмотреть файл

@ -49,8 +49,7 @@ this.pkcs11 = class extends ExtensionAPI {
}
if (
manifestLib !== ctypes.libraryName("nssckbi") &&
manifestLib !== ctypes.libraryName("osclientcerts") &&
manifestLib !== ctypes.libraryName("ipcclientcerts")
manifestLib !== ctypes.libraryName("osclientcerts")
) {
return hostInfo.manifest;
}

Просмотреть файл

@ -204,26 +204,6 @@ add_task(async function test_pkcs11() {
/No such PKCS#11 module osclientcerts/,
"getModuleSlots should not work on the built-in osclientcerts module"
);
await browser.test.assertRejects(
browser.pkcs11.installModule("ipcclientcerts", 0),
/No such PKCS#11 module ipcclientcerts/,
"installModule should not work on the built-in ipcclientcerts module"
);
await browser.test.assertRejects(
browser.pkcs11.uninstallModule("ipcclientcerts"),
/No such PKCS#11 module ipcclientcerts/,
"uninstallModule should not work on the built-in ipcclientcerts module"
);
await browser.test.assertRejects(
browser.pkcs11.isModuleInstalled("ipcclientcerts"),
/No such PKCS#11 module ipcclientcerts/,
"isModuleLoaded should not work on the built-in ipcclientcerts module"
);
await browser.test.assertRejects(
browser.pkcs11.getModuleSlots("ipcclientcerts"),
/No such PKCS#11 module ipcclientcerts/,
"getModuleSlots should not work on the built-in ipcclientcerts module"
);
browser.test.notifyPass("pkcs11");
} catch (e) {
browser.test.fail(`Error: ${String(e)} :: ${e.stack}`);

Просмотреть файл

@ -372,8 +372,6 @@ bin/libfreebl_64int_3.so
#endif
#endif
@BINPATH@/@DLL_PREFIX@ipcclientcerts@DLL_SUFFIX@
; For process sandboxing
#if defined(MOZ_SANDBOX)
#if defined(XP_LINUX)

Просмотреть файл

@ -15,7 +15,6 @@
#include "ssl.h"
#include "mozpkix/nss_scoped_ptrs.h"
#include "secerr.h"
#include "sslerr.h"
#include "mozilla/Sprintf.h"
#include "mozilla/dom/CryptoBuffer.h"
@ -25,103 +24,10 @@
namespace mozilla {
SECItem* WrapPrivateKeyInfoWithEmptyPassword(
SECKEYPrivateKey* pk) /* encrypt this private key */
{
if (!pk) {
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
return nullptr;
}
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
return nullptr;
}
// For private keys, NSS cannot export anything other than RSA, but we need EC
// also. So, we use the private key encryption function to serialize instead,
// using a hard-coded dummy password; this is not intended to provide any
// additional security, it just works around a limitation in NSS.
SECItem dummyPassword = {siBuffer, nullptr, 0};
UniqueSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo(
slot.get(), SEC_OID_AES_128_CBC, &dummyPassword, pk, 1, nullptr));
if (!epki) {
return nullptr;
}
return SEC_ASN1EncodeItem(
nullptr, nullptr, epki.get(),
NSS_Get_SECKEY_EncryptedPrivateKeyInfoTemplate(nullptr, false));
}
SECStatus UnwrapPrivateKeyInfoWithEmptyPassword(
SECItem* derPKI, const UniqueCERTCertificate& aCert,
SECKEYPrivateKey** privk) {
if (!derPKI || !aCert || !privk) {
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
return SECFailure;
}
UniqueSECKEYPublicKey publicKey(CERT_ExtractPublicKey(aCert.get()));
// This is a pointer to data inside publicKey
SECItem* publicValue = nullptr;
switch (publicKey->keyType) {
case dsaKey:
publicValue = &publicKey->u.dsa.publicValue;
break;
case dhKey:
publicValue = &publicKey->u.dh.publicValue;
break;
case rsaKey:
publicValue = &publicKey->u.rsa.modulus;
break;
case ecKey:
publicValue = &publicKey->u.ec.publicValue;
break;
default:
MOZ_ASSERT(false);
PR_SetError(SSL_ERROR_BAD_CERTIFICATE, 0);
return SECFailure;
}
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
return SECFailure;
}
UniquePLArenaPool temparena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
if (!temparena) {
return SECFailure;
}
SECKEYEncryptedPrivateKeyInfo* epki =
PORT_ArenaZNew(temparena.get(), SECKEYEncryptedPrivateKeyInfo);
if (!epki) {
return SECFailure;
}
SECStatus rv = SEC_ASN1DecodeItem(
temparena.get(), epki,
NSS_Get_SECKEY_EncryptedPrivateKeyInfoTemplate(nullptr, false), derPKI);
if (rv != SECSuccess) {
// If SEC_ASN1DecodeItem fails, we cannot assume anything about the
// validity of the data in epki. The best we can do is free the arena
// and return.
return rv;
}
// See comment in WrapPrivateKeyInfoWithEmptyPassword about this
// dummy password stuff.
SECItem dummyPassword = {siBuffer, nullptr, 0};
return PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
slot.get(), epki, &dummyPassword, nullptr, publicValue, false, false,
publicKey->keyType, KU_ALL, privk, nullptr);
}
nsresult DtlsIdentity::Serialize(nsTArray<uint8_t>* aKeyDer,
nsTArray<uint8_t>* aCertDer) {
ScopedSECItem derPki(WrapPrivateKeyInfoWithEmptyPassword(private_key_.get()));
ScopedSECItem derPki(
psm::WrapPrivateKeyInfoWithEmptyPassword(private_key_.get()));
if (!derPki) {
return NS_ERROR_FAILURE;
}
@ -144,7 +50,7 @@ RefPtr<DtlsIdentity> DtlsIdentity::Deserialize(
static_cast<unsigned int>(aKeyDer.Length())};
SECKEYPrivateKey* privateKey;
if (UnwrapPrivateKeyInfoWithEmptyPassword(&derPKI, cert, &privateKey) !=
if (psm::UnwrapPrivateKeyInfoWithEmptyPassword(&derPKI, cert, &privateKey) !=
SECSuccess) {
MOZ_ASSERT(false);
return nullptr;

Просмотреть файл

@ -56,7 +56,6 @@
#include "mozilla/dom/WebAuthnTransactionChild.h"
#include "mozilla/dom/MIDIPortChild.h"
#include "mozilla/dom/MIDIManagerChild.h"
#include "mozilla/psm/IPCClientCertsChild.h"
#include "mozilla/RemoteLazyInputStreamChild.h"
#include "nsID.h"
#include "nsTraceRefcnt.h"

Просмотреть файл

@ -71,8 +71,6 @@
#include "mozilla/net/HttpBackgroundChannelParent.h"
#include "mozilla/net/HttpConnectionMgrParent.h"
#include "mozilla/net/WebSocketConnectionParent.h"
#include "mozilla/psm/IPCClientCertsChild.h"
#include "mozilla/psm/IPCClientCertsParent.h"
#include "mozilla/psm/VerifySSLServerCertParent.h"
#include "nsIHttpChannelInternal.h"
#include "nsIPrincipal.h"
@ -1037,21 +1035,6 @@ mozilla::ipc::IPCResult BackgroundParentImpl::RecvPMessagePortConstructor(
return IPC_OK();
}
already_AddRefed<psm::PIPCClientCertsParent>
BackgroundParentImpl::AllocPIPCClientCertsParent() {
// This should only be called in the parent process with the socket process
// as the child process, not any content processes, hence the check that the
// child ID be 0.
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(mozilla::ipc::BackgroundParent::GetChildID(this) == 0);
if (!XRE_IsParentProcess() ||
mozilla::ipc::BackgroundParent::GetChildID(this) != 0) {
return nullptr;
}
RefPtr<psm::IPCClientCertsParent> result = new psm::IPCClientCertsParent();
return result.forget();
}
bool BackgroundParentImpl::DeallocPMessagePortParent(
PMessagePortParent* aActor) {
AssertIsInMainOrSocketProcess();

Просмотреть файл

@ -293,8 +293,6 @@ class BackgroundParentImpl : public PBackgroundParent,
PMessagePortParent* aActor, const nsID& aUUID,
const nsID& aDestinationUUID, const uint32_t& aSequenceID) override;
already_AddRefed<PIPCClientCertsParent> AllocPIPCClientCertsParent() override;
bool DeallocPMessagePortParent(PMessagePortParent* aActor) override;
mozilla::ipc::IPCResult RecvMessagePortForceClose(

Просмотреть файл

@ -25,7 +25,6 @@ include protocol PFileSystemRequest;
include protocol PGamepadEventChannel;
include protocol PGamepadTestChannel;
include protocol PHttpBackgroundChannel;
include protocol PIPCClientCerts;
include protocol PIdleScheduler;
include protocol PRemoteLazyInputStream;
include protocol PMediaTransport;
@ -106,7 +105,6 @@ sync protocol PBackground
manages PGamepadEventChannel;
manages PGamepadTestChannel;
manages PHttpBackgroundChannel;
manages PIPCClientCerts;
manages PIdleScheduler;
manages PRemoteLazyInputStream;
manages PLockManager;
@ -289,8 +287,6 @@ parent:
async PLockManager(ContentPrincipalInfo aPrincipalInfo, nsID aClientId);
async PIPCClientCerts();
child:
async PCache();
async PCacheStreamControl();

Просмотреть файл

@ -1072,10 +1072,6 @@ description = Reflection is cold code, but synchronous by spec.
# -
[PSocketProcess::GetTLSClientCert]
description = Synchronously get client certificate and key from parent process. Once bug 696976 has been fixed, this can be removed.
[PIPCClientCerts::FindObjects]
description = Finds certificates and private keys in the parent process. As this is called from PKCS#11, there is no way to make this asynchronous.
[PIPCClientCerts::Sign]
description = Performs a signature on given data with a key corresponding to the given identifier. This is called from PKCS#11, so there is no way to make this asynchronous.
#############################################################
# AVOID ADDING NEW MESSAGES TO THIS FILE #

Просмотреть файл

@ -66,8 +66,6 @@
@BINPATH@/@DLL_PREFIX@softokn3.chk
#endif
@BINPATH@/@DLL_PREFIX@ipcclientcerts@DLL_SUFFIX@
#ifndef MOZ_FOLD_LIBS
@BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
#endif

Просмотреть файл

@ -128,7 +128,7 @@ parent:
ByteArray aServerCert,
ByteArray? aClientCert,
ByteArray[] aCollectedCANames)
returns (bool aSucceeded, ByteArray aOutCert, ByteArray[] aBuiltChain);
returns (bool aSucceeded, ByteArray aOutCert, ByteArray aOutKey, ByteArray[] aBuiltChain);
async PProxyConfigLookup(nsIURI aUri, uint32_t aFlags);
async CachePushCheck(nsIURI aPushedURL,
OriginAttributes aOriginAttributes,

Просмотреть файл

@ -165,15 +165,7 @@ bool SocketProcessChild::Init(base::ProcessId aParentPid,
// Initialize DNS Service here, since it needs to be done in main thread.
nsCOMPtr<nsIDNSService> dns =
do_GetService("@mozilla.org/network/dns-service;1", &rv);
if (NS_FAILED(rv)) {
return false;
}
if (!EnsureNSSInitializedChromeOrContent()) {
return false;
}
return true;
return NS_SUCCEEDED(rv);
}
void SocketProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
@ -222,7 +214,6 @@ mozilla::ipc::IPCResult SocketProcessChild::RecvInit(
if (aAttributes.mInitSandbox()) {
Unused << RecvInitLinuxSandbox(aAttributes.mSandboxBroker());
}
return IPC_OK();
}
@ -481,7 +472,9 @@ SocketProcessChild::GetAndRemoveDataBridge(uint64_t aChannelId) {
}
mozilla::ipc::IPCResult SocketProcessChild::RecvClearSessionCache() {
nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();
if (EnsureNSSInitializedChromeOrContent()) {
nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();
}
return IPC_OK();
}

Просмотреть файл

@ -49,13 +49,11 @@ bool SocketProcessImpl::Init(int aArgc, char* aArgv[]) {
LoadLibraryW(L"nss3.dll");
LoadLibraryW(L"softokn3.dll");
LoadLibraryW(L"freebl3.dll");
LoadLibraryW(L"ipcclientcerts.dll");
mozilla::SandboxTarget::Instance()->StartSandbox();
#elif defined(__OpenBSD__) && defined(MOZ_SANDBOX)
PR_LoadLibrary("libnss3.so");
PR_LoadLibrary("libsoftokn3.so");
PR_LoadLibrary("libfreebl3.so");
PR_LoadLibrary("libipcclientcerts.so");
StartOpenBSDSandbox(GeckoProcessType_Socket);
#endif

Просмотреть файл

@ -25,7 +25,6 @@
#include "nsIConsoleService.h"
#include "nsIHttpActivityObserver.h"
#include "nsIObserverService.h"
#include "nsNSSComponent.h"
#include "nsNSSIOLayer.h"
#include "nsIOService.h"
#include "nsHttpHandler.h"
@ -312,7 +311,8 @@ mozilla::ipc::IPCResult SocketProcessParent::RecvGetTLSClientCert(
const int32_t& aPort, const uint32_t& aProviderFlags,
const uint32_t& aProviderTlsFlags, const ByteArray& aServerCert,
Maybe<ByteArray>&& aClientCert, nsTArray<ByteArray>&& aCollectedCANames,
bool* aSucceeded, ByteArray* aOutCert, nsTArray<ByteArray>* aBuiltChain) {
bool* aSucceeded, ByteArray* aOutCert, ByteArray* aOutKey,
nsTArray<ByteArray>* aBuiltChain) {
*aSucceeded = false;
SECItem serverCertItem = {
@ -342,15 +342,16 @@ mozilla::ipc::IPCResult SocketProcessParent::RecvGetTLSClientCert(
}
UniqueCERTCertificate cert;
UniqueSECKEYPrivateKey key;
UniqueCERTCertList builtChain;
SECStatus status =
DoGetClientAuthData(std::move(info), serverCert,
std::move(collectedCANames), cert, builtChain);
std::move(collectedCANames), cert, key, builtChain);
if (status != SECSuccess) {
return IPC_OK();
}
aOutCert->data().AppendElements(cert->derCert.data, cert->derCert.len);
SerializeClientCertAndKey(cert, key, *aOutCert, *aOutKey);
if (builtChain) {
for (CERTCertListNode* n = CERT_LIST_HEAD(builtChain);

Просмотреть файл

@ -99,14 +99,8 @@ class SocketProcessParent final
const int32_t& aPort, const uint32_t& aProviderFlags,
const uint32_t& aProviderTlsFlags, const ByteArray& aServerCert,
Maybe<ByteArray>&& aClientCert, nsTArray<ByteArray>&& aCollectedCANames,
bool* aSucceeded, ByteArray* aOutCert, nsTArray<ByteArray>* aBuiltChain);
mozilla::ipc::IPCResult RecvFindIPCClientCertObjects(
nsTArray<IPCClientCertObject>* aObjects);
mozilla::ipc::IPCResult RecvIPCClientCertSign(ByteArray aCert,
ByteArray aData,
ByteArray aParams,
ByteArray* aSignature);
bool* aSucceeded, ByteArray* aOutCert, ByteArray* aOutKey,
nsTArray<ByteArray>* aBuiltChain);
already_AddRefed<PProxyConfigLookupParent> AllocPProxyConfigLookupParent(
nsIURI* aURI, const uint32_t& aProxyResolveFlags);

Просмотреть файл

@ -20,7 +20,6 @@
#include "mozilla/AppShutdown.h"
#include "mozilla/Assertions.h"
#include "mozilla/Casting.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Services.h"
#include "mozilla/SyncRunnable.h"
@ -36,7 +35,6 @@
#include "nsNSSCertHelper.h"
#include "nsNSSCertificate.h"
#include "nsNSSCertificateDB.h"
#include "nsNSSIOLayer.h"
#include "nsPrintfCString.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
@ -1641,12 +1639,8 @@ void DisableMD5() {
NSS_USE_ALG_IN_CERT_SIGNATURE | NSS_USE_ALG_IN_CMS_SIGNATURE);
}
// Load a given PKCS#11 module located in the given directory. It will be named
// the given module name. Optionally pass some string parameters to it via
// 'params'. This argument will be provided to C_Initialize when called on the
// module.
bool LoadUserModuleAt(const char* moduleName, const char* libraryName,
const nsCString& dir, /* optional */ const char* params) {
const nsCString& dir) {
// If a module exists with the same name, make a best effort attempt to delete
// it. Note that it isn't possible to delete the internal module, so checking
// the return value would be detrimental in that case.
@ -1670,11 +1664,6 @@ bool LoadUserModuleAt(const char* moduleName, const char* libraryName,
pkcs11ModuleSpec.AppendLiteral("\" library=\"");
pkcs11ModuleSpec.Append(fullLibraryPath);
pkcs11ModuleSpec.AppendLiteral("\"");
if (params) {
pkcs11ModuleSpec.AppendLiteral("\" parameters=\"");
pkcs11ModuleSpec.Append(params);
pkcs11ModuleSpec.AppendLiteral("\"");
}
UniqueSECMODModule userModule(SECMOD_LoadUserModule(
const_cast<char*>(pkcs11ModuleSpec.get()), nullptr, false));
@ -1689,31 +1678,6 @@ bool LoadUserModuleAt(const char* moduleName, const char* libraryName,
return true;
}
const char* kIPCClientCertsModuleName = "IPC Client Cert Module";
bool LoadIPCClientCertsModule(const nsCString& dir) {
// The IPC client certs module needs to be able to call back into gecko to be
// able to communicate with the parent process over IPC. This is achieved by
// serializing the addresses of the relevant functions and passing them as an
// extra string parameter that will be available when C_Initialize is called
// on IPC client certs.
nsPrintfCString addrs("%p,%p", DoFindObjects, DoSign);
if (!LoadUserModuleAt(kIPCClientCertsModuleName, "ipcclientcerts", dir,
addrs.get())) {
return false;
}
RunOnShutdown(
[]() {
UniqueSECMODModule ipcClientCertsModule(
SECMOD_FindModule(kIPCClientCertsModuleName));
if (ipcClientCertsModule) {
SECMOD_UnloadUserModule(ipcClientCertsModule.get());
}
},
ShutdownPhase::XPCOMWillShutdown);
return true;
}
const char* kOSClientCertsModuleName = "OS Client Cert Module";
bool LoadOSClientCertsModule(const nsCString& dir) {
@ -1723,8 +1687,7 @@ bool LoadOSClientCertsModule(const nsCString& dir) {
return false;
}
#endif
return LoadUserModuleAt(kOSClientCertsModuleName, "osclientcerts", dir,
nullptr);
return LoadUserModuleAt(kOSClientCertsModuleName, "osclientcerts", dir);
}
bool LoadLoadableRoots(const nsCString& dir) {
@ -1735,7 +1698,7 @@ bool LoadLoadableRoots(const nsCString& dir) {
// "Root Certs" module allows us to load the correct one. See bug 1406396.
int unusedModType;
Unused << SECMOD_DeleteModule("Root Certs", &unusedModType);
return LoadUserModuleAt(kRootModuleName, "nssckbi", dir, nullptr);
return LoadUserModuleAt(kRootModuleName, "nssckbi", dir);
}
nsresult DefaultServerNicknameForCert(const CERTCertificate* cert,

Просмотреть файл

@ -76,23 +76,6 @@ bool LoadOSClientCertsModule(const nsCString& dir);
extern const char* kOSClientCertsModuleName;
/**
* Loads the IPC client certs module.
*
* @param dir
* The path to the directory containing the module. This should be the
* same as where all of the other gecko libraries live.
* @return true if the module was successfully loaded, false otherwise.
*/
bool LoadIPCClientCertsModule(const nsCString& dir);
extern const char* kIPCClientCertsModuleName;
/**
* Unloads the loadable roots module and os client certs module, if loaded.
*/
void UnloadUserModules();
nsresult DefaultServerNicknameForCert(const CERTCertificate* cert,
/*out*/ nsCString& nickname);

Просмотреть файл

@ -1,17 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IPCClientCertsChild.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
namespace mozilla::psm {
IPCClientCertsChild::IPCClientCertsChild() = default;
} // namespace mozilla::psm

Просмотреть файл

@ -1,36 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_psm_IPCClientCertsChild_h__
#define mozilla_psm_IPCClientCertsChild_h__
#include "mozilla/psm/PIPCClientCertsChild.h"
namespace mozilla {
namespace ipc {
class BackgroundChildImpl;
} // namespace ipc
namespace psm {
class IPCClientCertsChild final : public PIPCClientCertsChild {
friend class mozilla::ipc::BackgroundChildImpl;
public:
IPCClientCertsChild();
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(IPCClientCertsChild);
private:
~IPCClientCertsChild() = default;
};
} // namespace psm
} // namespace mozilla
#endif

Просмотреть файл

@ -1,114 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IPCClientCertsParent.h"
#include "mozilla/ipc/BackgroundParent.h"
namespace mozilla::psm {
IPCClientCertsParent::IPCClientCertsParent() = default;
// When the IPC client certs module needs to find certificate and key objects
// in the socket process, it will cause this function to be called in the
// parent process. The parent process needs to find all certificates with
// private keys (because these are potential client certificates).
mozilla::ipc::IPCResult IPCClientCertsParent::RecvFindObjects(
nsTArray<IPCClientCertObject>* aObjects) {
UniqueCERTCertList certList(psm::FindClientCertificatesWithPrivateKeys());
if (!certList) {
return IPC_OK();
}
CERTCertListNode* n = CERT_LIST_HEAD(certList);
while (!CERT_LIST_END(n, certList)) {
nsTArray<uint8_t> certDER(n->cert->derCert.data, n->cert->derCert.len);
uint32_t slotType;
UniqueSECKEYPublicKey pubkey(CERT_ExtractPublicKey(n->cert));
if (!pubkey) {
return IPC_OK();
}
switch (SECKEY_GetPublicKeyType(pubkey.get())) {
case rsaKey:
case rsaPssKey: {
slotType = PK11_DoesMechanism(n->cert->slot, CKM_RSA_PKCS_PSS)
? kIPCClientCertsSlotTypeModern
: kIPCClientCertsSlotTypeLegacy;
nsTArray<uint8_t> modulus(pubkey->u.rsa.modulus.data,
pubkey->u.rsa.modulus.len);
RSAKey rsakey(modulus, certDER, slotType);
aObjects->AppendElement(std::move(rsakey));
break;
}
case ecKey: {
slotType = kIPCClientCertsSlotTypeModern;
nsTArray<uint8_t> params(pubkey->u.ec.DEREncodedParams.data,
pubkey->u.ec.DEREncodedParams.len);
ECKey eckey(params, certDER, slotType);
aObjects->AppendElement(std::move(eckey));
break;
}
default:
n = CERT_LIST_NEXT(n);
continue;
}
Certificate cert(certDER, slotType);
aObjects->AppendElement(std::move(cert));
n = CERT_LIST_NEXT(n);
}
return IPC_OK();
}
// When the IPC client certs module needs to sign data using a key managed by
// the parent process, it will cause this function to be called in the parent
// process. The parent process needs to find the key corresponding to the given
// certificate and sign the given data with the given parameters.
mozilla::ipc::IPCResult IPCClientCertsParent::RecvSign(ByteArray aCert,
ByteArray aData,
ByteArray aParams,
ByteArray* aSignature) {
SECItem certItem = {siBuffer, const_cast<uint8_t*>(aCert.data().Elements()),
static_cast<unsigned int>(aCert.data().Length())};
aSignature->data().Clear();
UniqueCERTCertificate cert(CERT_NewTempCertificate(
CERT_GetDefaultCertDB(), &certItem, nullptr, false, true));
if (!cert) {
return IPC_OK();
}
UniqueSECKEYPrivateKey key(PK11_FindKeyByAnyCert(cert.get(), nullptr));
if (!key) {
return IPC_OK();
}
SECItem params = {siBuffer, aParams.data().Elements(),
static_cast<unsigned int>(aParams.data().Length())};
SECItem* paramsPtr = aParams.data().Length() > 0 ? &params : nullptr;
CK_MECHANISM_TYPE mechanism;
switch (key->keyType) {
case ecKey:
mechanism = CKM_ECDSA;
break;
case rsaKey:
mechanism = aParams.data().Length() > 0 ? CKM_RSA_PKCS_PSS : CKM_RSA_PKCS;
break;
default:
return IPC_OK();
}
uint32_t len = PK11_SignatureLen(key.get());
UniqueSECItem sig(::SECITEM_AllocItem(nullptr, nullptr, len));
SECItem hash = {siBuffer, aData.data().Elements(),
static_cast<unsigned int>(aData.data().Length())};
SECStatus srv =
PK11_SignWithMechanism(key.get(), mechanism, paramsPtr, sig.get(), &hash);
if (srv != SECSuccess) {
return IPC_OK();
}
aSignature->data().AppendElements(sig->data, sig->len);
return IPC_OK();
}
} // namespace mozilla::psm

Просмотреть файл

@ -1,40 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_psm_IPCClientCertsParent_h__
#define mozilla_psm_IPCClientCertsParent_h__
#include "mozilla/psm/PIPCClientCertsParent.h"
namespace mozilla {
namespace ipc {
class BackgroundParentImpl;
} // namespace ipc
namespace psm {
class IPCClientCertsParent final : public PIPCClientCertsParent {
friend class mozilla::ipc::BackgroundParentImpl;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(IPCClientCertsParent)
mozilla::ipc::IPCResult RecvFindObjects(
nsTArray<IPCClientCertObject>* aObjects);
mozilla::ipc::IPCResult RecvSign(ByteArray aCert, ByteArray aData,
ByteArray aParams, ByteArray* aSignature);
private:
IPCClientCertsParent();
~IPCClientCertsParent() = default;
};
} // namespace psm
} // namespace mozilla
#endif

Просмотреть файл

@ -1,35 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBackground;
include PSMIPCTypes;
using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
namespace mozilla {
namespace psm {
[RefCounted] sync protocol PIPCClientCerts
{
manager PBackground;
parent:
// Called from the socket process to the parent process to find client
// certificates and associated keys.
sync FindObjects() returns (IPCClientCertObject[] aObjects);
// Called from the socket process to the parent process to sign the given
// data with the given parameters using the key associated with the given
// certificate. Used when a TLS server requests a client authentication
// certificate.
sync Sign(ByteArray aCert, ByteArray aData, ByteArray aParams)
returns (ByteArray aSignature);
async __delete__();
};
} // namespace psm
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,161 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CTVerifyResult.h"
#include "PSMIPCCommon.h"
namespace mozilla {
namespace psm {
SECItem* WrapPrivateKeyInfoWithEmptyPassword(
SECKEYPrivateKey* pk) /* encrypt this private key */
{
if (!pk) {
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
return nullptr;
}
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
return nullptr;
}
// For private keys, NSS cannot export anything other than RSA, but we need EC
// also. So, we use the private key encryption function to serialize instead,
// using a hard-coded dummy password; this is not intended to provide any
// additional security, it just works around a limitation in NSS.
SECItem dummyPassword = {siBuffer, nullptr, 0};
UniqueSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo(
slot.get(), SEC_OID_AES_128_CBC, &dummyPassword, pk, 1, nullptr));
if (!epki) {
return nullptr;
}
return SEC_ASN1EncodeItem(
nullptr, nullptr, epki.get(),
NSS_Get_SECKEY_EncryptedPrivateKeyInfoTemplate(nullptr, false));
}
SECStatus UnwrapPrivateKeyInfoWithEmptyPassword(
SECItem* derPKI, const UniqueCERTCertificate& aCert,
SECKEYPrivateKey** privk) {
if (!derPKI || !aCert || !privk) {
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
return SECFailure;
}
UniqueSECKEYPublicKey publicKey(CERT_ExtractPublicKey(aCert.get()));
// This is a pointer to data inside publicKey
SECItem* publicValue = nullptr;
switch (publicKey->keyType) {
case dsaKey:
publicValue = &publicKey->u.dsa.publicValue;
break;
case dhKey:
publicValue = &publicKey->u.dh.publicValue;
break;
case rsaKey:
publicValue = &publicKey->u.rsa.modulus;
break;
case ecKey:
publicValue = &publicKey->u.ec.publicValue;
break;
default:
MOZ_ASSERT(false);
PR_SetError(SSL_ERROR_BAD_CERTIFICATE, 0);
return SECFailure;
}
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
return SECFailure;
}
UniquePLArenaPool temparena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
if (!temparena) {
return SECFailure;
}
SECKEYEncryptedPrivateKeyInfo* epki =
PORT_ArenaZNew(temparena.get(), SECKEYEncryptedPrivateKeyInfo);
if (!epki) {
return SECFailure;
}
SECStatus rv = SEC_ASN1DecodeItem(
temparena.get(), epki,
NSS_Get_SECKEY_EncryptedPrivateKeyInfoTemplate(nullptr, false), derPKI);
if (rv != SECSuccess) {
// If SEC_ASN1DecodeItem fails, we cannot assume anything about the
// validity of the data in epki. The best we can do is free the arena
// and return.
return rv;
}
// See comment in WrapPrivateKeyInfoWithEmptyPassword about this
// dummy password stuff.
SECItem dummyPassword = {siBuffer, nullptr, 0};
return PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
slot.get(), epki, &dummyPassword, nullptr, publicValue, false, false,
publicKey->keyType, KU_ALL, privk, nullptr);
}
void SerializeClientCertAndKey(const UniqueCERTCertificate& aCert,
const UniqueSECKEYPrivateKey& aKey,
ByteArray& aOutSerializedCert,
ByteArray& aOutSerializedKey) {
if (!aCert || !aKey) {
return;
}
UniqueSECItem derPki(WrapPrivateKeyInfoWithEmptyPassword(aKey.get()));
if (!derPki) {
return;
}
aOutSerializedCert.data().AppendElements(aCert->derCert.data,
aCert->derCert.len);
aOutSerializedKey.data().AppendElements(derPki->data, derPki->len);
}
void DeserializeClientCertAndKey(const ByteArray& aSerializedCert,
const ByteArray& aSerializedKey,
UniqueCERTCertificate& aOutCert,
UniqueSECKEYPrivateKey& aOutKey) {
if (aSerializedCert.data().IsEmpty() || aSerializedKey.data().IsEmpty()) {
return;
}
SECItem item = {siBuffer,
const_cast<uint8_t*>(aSerializedCert.data().Elements()),
static_cast<unsigned int>(aSerializedCert.data().Length())};
UniqueCERTCertificate cert(CERT_NewTempCertificate(
CERT_GetDefaultCertDB(), &item, nullptr, false, true));
if (!cert) {
return;
}
SECItem derPKI = {siBuffer,
const_cast<uint8_t*>(aSerializedKey.data().Elements()),
static_cast<unsigned int>(aSerializedKey.data().Length())};
SECKEYPrivateKey* privateKey;
if (UnwrapPrivateKeyInfoWithEmptyPassword(&derPKI, cert, &privateKey) !=
SECSuccess) {
MOZ_ASSERT(false);
return;
}
aOutCert = std::move(cert);
aOutKey.reset(privateKey);
}
} // namespace psm
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,34 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef PSMIPCCommon_h__
#define PSMIPCCommon_h__
#include "mozilla/psm/PSMIPCTypes.h"
#include "seccomon.h"
#include "ScopedNSSTypes.h"
namespace mozilla {
namespace psm {
SECItem* WrapPrivateKeyInfoWithEmptyPassword(SECKEYPrivateKey* pk);
SECStatus UnwrapPrivateKeyInfoWithEmptyPassword(
SECItem* derPKI, const UniqueCERTCertificate& aCert,
SECKEYPrivateKey** privk);
void SerializeClientCertAndKey(const UniqueCERTCertificate& aCert,
const UniqueSECKEYPrivateKey& aKey,
ByteArray& aOutSerializedCert,
ByteArray& aOutSerializedKey);
void DeserializeClientCertAndKey(const ByteArray& aSerializedCert,
const ByteArray& aSerializedKey,
UniqueCERTCertificate& aOutCert,
UniqueSECKEYPrivateKey& aOutKey);
} // namespace psm
} // namespace mozilla
#endif // PSMIPCCommon_h__

Просмотреть файл

@ -12,36 +12,6 @@ struct ByteArray{
uint8_t[] data;
};
// For ECKey, RSAKey, and Certificate, slotType indicates which slot this object
// should exist on:
// 1: modern (supports EC, RSA-PSS)
// 2: legacy (only supports RSA PKCS#1v1.5)
struct ECKey{
uint8_t[] params; // the EC point representing this key
uint8_t[] cert; // the encoded certificate containing this key
uint32_t slotType;
};
struct RSAKey{
uint8_t[] modulus; // the modulus of this RSA key
uint8_t[] cert; // the encoded certificate containing this key
uint32_t slotType;
};
struct Certificate{
uint8_t[] der; // the encoding of this certificate
uint32_t slotType;
};
// Helper type for sending keys and certificates over IPC for use by IPC client
// certs.
union IPCClientCertObject{
ECKey;
RSAKey;
Certificate;
};
struct DelegatedCredentialInfoArg {
uint32_t scheme;
uint32_t authKeyBits;

Просмотреть файл

@ -1,15 +0,0 @@
[package]
name = "ipcclientcerts-static"
version = "0.1.0"
authors = ["Dana Keeler <dkeeler@mozilla.com>"]
edition = "2018"
[dependencies]
byteorder = "1.3"
once_cell = "1"
pkcs11 = "0.4"
rsclientcerts = { path = "../rsclientcerts" }
sha2 = "0.8"
[lib]
crate-type = ["staticlib"]

Просмотреть файл

@ -1 +0,0 @@
C_GetFunctionList

Просмотреть файл

@ -1,42 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
USE_LIBS += ["ipcclientcerts-static"]
# On Linux (but not when building for Android), this needs to use the C++
# version to avoid linking against the wrong libc symbols.
# On Android, this needs to use the C version to avoid multiple definitions
# of symbols caused by their presence in libgcc and ipcclientcerts-static.
if CONFIG["OS_ARCH"] == "Linux" and CONFIG["OS_TARGET"] != "Android":
SOURCES += [
"stub.cpp",
]
else:
SOURCES += [
"stub.c",
]
if CONFIG["OS_TARGET"] == "Android":
OS_LIBS += ["m"]
if CONFIG["OS_ARCH"] == "WINNT":
OS_LIBS += [
"userenv",
"ws2_32",
]
# Version string comparison is generally wrong, but by the time it would
# actually matter, either bug 1489995 would be fixed, or the build would
# require version >= 1.57.
if CONFIG["RUSTC_VERSION"] and CONFIG["RUSTC_VERSION"] >= "1.57.0":
OS_LIBS += [
"bcrypt",
]
SharedLibrary("ipcclientcerts")
NoVisibilityFlags()
SYMBOLS_FILE = "ipcclientcerts.symbols"

Просмотреть файл

@ -1,26 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "pkcs11.h"
// The build system builds the rust library ipcclientcerts as a static library
// called ipcclientcerts_static. On macOS and Windows, that static library can
// be linked with an empty file and turned into a shared library with the
// function C_GetFunctionList exposed. This allows that shared library to be
// used as a PKCS#11 module (see osclientcerts).
// Unfortunately, on Linux, exposing the C_GetFunctionList in the static
// library doesn't work for some unknown reason. As a workaround, this file
// declares its own C_GetFunctionList that can be exposed in the shared
// library. It then calls the function IPCCC_GetFunctionList exposed
// (internally to the linkage in question) by ipcclientcerts. This enables
// the build system to ultimately turn ipcclientcerts into a shared library
// that exposes a C_GetFunctionList function, meaning it can be used as a
// PKCS#11 module.
CK_RV IPCCC_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList);
CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) {
return IPCCC_GetFunctionList(ppFunctionList);
}

Просмотреть файл

@ -1,29 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "pkcs11.h"
// The build system builds the rust library ipcclientcerts as a static library
// called ipcclientcerts_static. On macOS and Windows, that static library can
// be linked with an empty file and turned into a shared library with the
// function C_GetFunctionList exposed. This allows that shared library to be
// used as a PKCS#11 module (see osclientcerts).
// Unfortunately, on Linux, exposing the C_GetFunctionList in the static
// library doesn't work for some unknown reason. As a workaround, this file
// declares its own C_GetFunctionList that can be exposed in the shared
// library. It then calls the function IPCCC_GetFunctionList exposed
// (internally to the linkage in question) by ipcclientcerts. This enables
// the build system to ultimately turn ipcclientcerts into a shared library
// that exposes a C_GetFunctionList function, meaning it can be used as a
// PKCS#11 module.
extern "C" {
CK_RV IPCCC_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList);
CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) {
return IPCCC_GetFunctionList(ppFunctionList);
}
}

Просмотреть файл

@ -1,9 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += ["dynamic-library"]
RustLibrary("ipcclientcerts-static")

Просмотреть файл

@ -1,373 +0,0 @@
/* -*- Mode: rust; rust-indent-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use pkcs11::types::*;
use rsclientcerts::error::{Error, ErrorType};
use rsclientcerts::manager::{ClientCertsBackend, CryptokiObject, Sign, SlotType};
use rsclientcerts::util::*;
use sha2::{Digest, Sha256};
use std::ffi::c_void;
use crate::FindObjectsFunction;
use crate::SignFunction;
pub struct Cert {
class: Vec<u8>,
token: Vec<u8>,
id: Vec<u8>,
label: Vec<u8>,
value: Vec<u8>,
issuer: Vec<u8>,
serial_number: Vec<u8>,
subject: Vec<u8>,
slot_type: SlotType,
}
impl Cert {
fn new(der: &[u8], slot_type: SlotType) -> Result<Cert, Error> {
let (serial_number, issuer, subject) = read_encoded_certificate_identifiers(der)?;
let id = Sha256::digest(der).to_vec();
Ok(Cert {
class: serialize_uint(CKO_CERTIFICATE)?,
token: serialize_uint(CK_TRUE)?,
id,
label: b"IPC certificate".to_vec(),
value: der.to_vec(),
issuer,
serial_number,
subject,
slot_type,
})
}
fn class(&self) -> &[u8] {
&self.class
}
fn token(&self) -> &[u8] {
&self.token
}
fn id(&self) -> &[u8] {
&self.id
}
fn label(&self) -> &[u8] {
&self.label
}
fn value(&self) -> &[u8] {
&self.value
}
fn issuer(&self) -> &[u8] {
&self.issuer
}
fn serial_number(&self) -> &[u8] {
&self.serial_number
}
fn subject(&self) -> &[u8] {
&self.subject
}
}
impl CryptokiObject for Cert {
fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
if self.slot_type != slot_type {
return false;
}
for (attr_type, attr_value) in attrs {
let comparison = match *attr_type {
CKA_CLASS => self.class(),
CKA_TOKEN => self.token(),
CKA_LABEL => self.label(),
CKA_ID => self.id(),
CKA_VALUE => self.value(),
CKA_ISSUER => self.issuer(),
CKA_SERIAL_NUMBER => self.serial_number(),
CKA_SUBJECT => self.subject(),
_ => return false,
};
if attr_value.as_slice() != comparison {
return false;
}
}
true
}
fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
let result = match attribute {
CKA_CLASS => self.class(),
CKA_TOKEN => self.token(),
CKA_LABEL => self.label(),
CKA_ID => self.id(),
CKA_VALUE => self.value(),
CKA_ISSUER => self.issuer(),
CKA_SERIAL_NUMBER => self.serial_number(),
CKA_SUBJECT => self.subject(),
_ => return None,
};
Some(result)
}
}
pub struct Key {
cert: Vec<u8>,
class: Vec<u8>,
token: Vec<u8>,
id: Vec<u8>,
private: Vec<u8>,
key_type: Vec<u8>,
modulus: Option<Vec<u8>>,
ec_params: Option<Vec<u8>>,
slot_type: SlotType,
sign: SignFunction,
}
impl Key {
fn new(
modulus: Option<&[u8]>,
ec_params: Option<&[u8]>,
cert: &[u8],
slot_type: SlotType,
sign: SignFunction,
) -> Result<Key, Error> {
let id = Sha256::digest(cert).to_vec();
let key_type = if modulus.is_some() { CKK_RSA } else { CKK_EC };
Ok(Key {
cert: cert.to_vec(),
class: serialize_uint(CKO_PRIVATE_KEY)?,
token: serialize_uint(CK_TRUE)?,
id,
private: serialize_uint(CK_TRUE)?,
key_type: serialize_uint(key_type)?,
modulus: modulus.map(|b| b.to_vec()),
ec_params: ec_params.map(|b| b.to_vec()),
slot_type,
sign,
})
}
fn class(&self) -> &[u8] {
&self.class
}
fn token(&self) -> &[u8] {
&self.token
}
pub fn id(&self) -> &[u8] {
&self.id
}
fn private(&self) -> &[u8] {
&self.private
}
fn key_type(&self) -> &[u8] {
&self.key_type
}
fn modulus(&self) -> Option<&[u8]> {
match &self.modulus {
Some(modulus) => Some(modulus.as_slice()),
None => None,
}
}
fn ec_params(&self) -> Option<&[u8]> {
match &self.ec_params {
Some(ec_params) => Some(ec_params.as_slice()),
None => None,
}
}
}
impl CryptokiObject for Key {
fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
if self.slot_type != slot_type {
return false;
}
for (attr_type, attr_value) in attrs {
let comparison = match *attr_type {
CKA_CLASS => self.class(),
CKA_TOKEN => self.token(),
CKA_ID => self.id(),
CKA_PRIVATE => self.private(),
CKA_KEY_TYPE => self.key_type(),
CKA_MODULUS => {
if let Some(modulus) = self.modulus() {
modulus
} else {
return false;
}
}
CKA_EC_PARAMS => {
if let Some(ec_params) = self.ec_params() {
ec_params
} else {
return false;
}
}
_ => return false,
};
if attr_value.as_slice() != comparison {
return false;
}
}
true
}
fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
match attribute {
CKA_CLASS => Some(self.class()),
CKA_TOKEN => Some(self.token()),
CKA_ID => Some(self.id()),
CKA_PRIVATE => Some(self.private()),
CKA_KEY_TYPE => Some(self.key_type()),
CKA_MODULUS => self.modulus(),
CKA_EC_PARAMS => self.ec_params(),
_ => None,
}
}
}
impl Sign for Key {
fn get_signature_length(
&mut self,
data: &[u8],
params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
) -> Result<usize, Error> {
// Unfortunately we don't have a way of getting the length of a signature without creating
// one.
let dummy_signature_bytes = self.sign(data, params)?;
Ok(dummy_signature_bytes.len())
}
fn sign(
&mut self,
data: &[u8],
params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
) -> Result<Vec<u8>, Error> {
let mut signature = Vec::new();
let (params_len, params) = match params {
Some(params) => (
std::mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>(),
params as *const _ as *const u8,
),
None => (0, std::ptr::null()),
};
(self.sign)(
self.cert.len(),
self.cert.as_ptr(),
data.len(),
data.as_ptr(),
params_len,
params,
Some(sign_callback),
&mut signature as *mut _ as *mut c_void,
);
if signature.len() > 0 {
Ok(signature)
} else {
Err(error_here!(ErrorType::LibraryFailure))
}
}
}
unsafe extern "C" fn sign_callback(data_len: usize, data: *const u8, ctx: *mut c_void) {
let signature: &mut Vec<u8> = std::mem::transmute(ctx);
signature.clear();
signature.extend_from_slice(std::slice::from_raw_parts(data, data_len));
}
unsafe extern "C" fn find_objects_callback(
typ: u8,
data_len: usize,
data: *const u8,
extra_len: usize,
extra: *const u8,
slot_type: u32,
ctx: *mut c_void,
) {
let data = std::slice::from_raw_parts(data, data_len);
let extra = std::slice::from_raw_parts(extra, extra_len);
let slot_type = match slot_type {
1 => SlotType::Modern,
2 => SlotType::Legacy,
_ => return,
};
let find_objects_context: &mut FindObjectsContext = std::mem::transmute(ctx);
match typ {
1 => match Cert::new(data, slot_type) {
Ok(cert) => find_objects_context.certs.push(cert),
Err(_) => {}
},
2 => match Key::new(
Some(data),
None,
extra,
slot_type,
find_objects_context.sign,
) {
Ok(key) => find_objects_context.keys.push(key),
Err(_) => {}
},
3 => match Key::new(
None,
Some(data),
extra,
slot_type,
find_objects_context.sign,
) {
Ok(key) => find_objects_context.keys.push(key),
Err(_) => {}
},
_ => {}
}
}
struct FindObjectsContext {
certs: Vec<Cert>,
keys: Vec<Key>,
sign: SignFunction,
}
impl FindObjectsContext {
fn new(sign: SignFunction) -> FindObjectsContext {
FindObjectsContext {
certs: Vec::new(),
keys: Vec::new(),
sign,
}
}
}
pub struct Backend {
find_objects: FindObjectsFunction,
sign: SignFunction,
}
impl Backend {
pub fn new(find_objects: FindObjectsFunction, sign: SignFunction) -> Backend {
Backend { find_objects, sign }
}
}
impl ClientCertsBackend for Backend {
type Cert = Cert;
type Key = Key;
fn find_objects(&self) -> Result<(Vec<Cert>, Vec<Key>), Error> {
let mut find_objects_context = FindObjectsContext::new(self.sign);
(self.find_objects)(
Some(find_objects_callback),
&mut find_objects_context as *mut _ as *mut c_void,
);
Ok((find_objects_context.certs, find_objects_context.keys))
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -12,8 +12,6 @@ if (CONFIG["OS_ARCH"] == "WINNT" and CONFIG["CPU_ARCH"] != "aarch64") or CONFIG[
] == "Darwin":
DIRS += ["osclientcerts"]
DIRS += ["ipcclientcerts"]
TEST_DIRS += ["tests"]
XPIDL_SOURCES += [
@ -91,8 +89,6 @@ EXPORTS.mozilla += [
]
EXPORTS.mozilla.psm += [
"IPCClientCertsChild.h",
"IPCClientCertsParent.h",
"PSMIPCCommon.h",
"TransportSecurityInfo.h",
"VerifySSLServerCertChild.h",
@ -111,8 +107,6 @@ UNIFIED_SOURCES += [
"CSTrustDomain.cpp",
"DataStorage.cpp",
"EnterpriseRoots.cpp",
"IPCClientCertsChild.cpp",
"IPCClientCertsParent.cpp",
"LocalCertService.cpp",
"nsCertOverrideService.cpp",
"nsClientAuthRemember.cpp",
@ -191,7 +185,6 @@ if CONFIG["OS_ARCH"] == "WINNT":
]
IPDL_SOURCES += [
"PIPCClientCerts.ipdl",
"PSMIPCTypes.ipdlh",
"PVerifySSLServerCert.ipdl",
]
@ -208,7 +201,6 @@ LOCAL_INCLUDES += [
"/dom/crypto",
"/netwerk/base",
"/security/certverifier",
"/xpcom/build",
]
LOCAL_INCLUDES += [

Просмотреть файл

@ -13,7 +13,6 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Casting.h"
#include "mozilla/Logging.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Span.h"
#include "mozilla/Telemetry.h"

Просмотреть файл

@ -6,7 +6,6 @@
#include "nsNSSComponent.h"
#include "BinaryPath.h"
#include "CryptoTask.h"
#include "EnterpriseRoots.h"
#include "ExtendedValidation.h"
@ -22,7 +21,6 @@
#include "mozilla/Assertions.h"
#include "mozilla/Casting.h"
#include "mozilla/EndianUtils.h"
#include "mozilla/FilePreferences.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Preferences.h"
#include "mozilla/ProfilerLabels.h"
@ -102,38 +100,6 @@ int nsNSSComponent::mInstanceCount = 0;
// Forward declaration.
nsresult CommonInit();
// Take an nsIFile and get a c-string representation of the location of that
// file (encapsulated in an nsACString). This function handles a
// platform-specific issue on Windows where Unicode characters that cannot be
// mapped to the system's codepage will be dropped, resulting in a c-string
// that is useless to describe the location of the file in question.
// This operation is generally to be avoided, except when interacting with
// third-party or legacy libraries that cannot handle `nsIFile`s (such as NSS).
nsresult FileToCString(const nsCOMPtr<nsIFile>& file, nsACString& result) {
#ifdef XP_WIN
// Native path will drop Unicode characters that cannot be mapped to system's
// codepage, using short (canonical) path as workaround.
nsCOMPtr<nsILocalFileWin> fileWin = do_QueryInterface(file);
if (!fileWin) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get nsILocalFileWin"));
return NS_ERROR_FAILURE;
}
return fileWin->GetNativeCanonicalPath(result);
#else
return file->GetNativePath(result);
#endif
}
void TruncateFromLastDirectorySeparator(nsCString& path) {
static const nsAutoCString kSeparatorString(
mozilla::FilePreferences::kPathSeparator);
int32_t index = path.RFind(kSeparatorString);
if (index == kNotFound) {
return;
}
path.Truncate(index);
}
// This function can be called from chrome or content or socket processes
// to ensure that NSS is initialized.
bool EnsureNSSInitializedChromeOrContent() {
@ -183,36 +149,6 @@ bool EnsureNSSInitializedChromeOrContent() {
if (NS_FAILED(CommonInit())) {
return false;
}
// This returns the path to the binary currently running, which in most
// cases is "plugin-container".
UniqueFreePtr<char> pluginContainerPath(BinaryPath::Get());
if (!pluginContainerPath) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("failed to get get plugin-container path"));
return false;
}
nsAutoCString ipcClientCertsDirString(pluginContainerPath.get());
// On most platforms, ipcclientcerts is in the same directory as
// plugin-container. To obtain the path to that directory, truncate from
// the last directory separator.
// On macOS, plugin-container is in
// Firefox.app/Contents/MacOS/plugin-container.app/Contents/MacOS/,
// whereas ipcclientcerts is in Firefox.app/Contents/MacOS/. Consequently,
// this truncation from the last directory separator has to happen 4 times
// total. Normally this would be done using nsIFile APIs, but due to when
// this is initialized in the socket process, those aren't available.
TruncateFromLastDirectorySeparator(ipcClientCertsDirString);
#ifdef XP_MACOSX
TruncateFromLastDirectorySeparator(ipcClientCertsDirString);
TruncateFromLastDirectorySeparator(ipcClientCertsDirString);
TruncateFromLastDirectorySeparator(ipcClientCertsDirString);
#endif
if (!LoadIPCClientCertsModule(ipcClientCertsDirString)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("failed to load ipcclientcerts from '%s'",
ipcClientCertsDirString.get()));
return false;
}
initialized = true;
return true;
}
@ -282,6 +218,8 @@ void nsNSSComponent::GetRevocationBehaviorFromPrefs(
hardTimeoutMillis =
std::min(hardTimeoutMillis, OCSP_TIMEOUT_MILLISECONDS_HARD_MAX);
hardTimeout = TimeDuration::FromMilliseconds(hardTimeoutMillis);
ClearSSLExternalAndInternalSessionCache();
}
nsNSSComponent::nsNSSComponent()
@ -569,7 +507,6 @@ void nsNSSComponent::UnloadEnterpriseRoots() {
MutexAutoLock lock(mMutex);
mEnterpriseCerts.clear();
setValidationOptions(false, lock);
ClearSSLExternalAndInternalSessionCache();
}
static const char* kEnterpriseRootModePref =
@ -814,7 +751,18 @@ static nsresult GetDirectoryPath(const char* directoryKey, nsCString& result) {
("could not get '%s' from directory service", directoryKey));
return rv;
}
return FileToCString(directory, result);
#ifdef XP_WIN
// Native path will drop Unicode characters that cannot be mapped to system's
// codepage, using short (canonical) path as workaround.
nsCOMPtr<nsILocalFileWin> directoryWin = do_QueryInterface(directory);
if (!directoryWin) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get nsILocalFileWin"));
return NS_ERROR_FAILURE;
}
return directoryWin->GetNativeCanonicalPath(result);
#else
return directory->GetNativePath(result);
#endif
}
class BackgroundLoadOSClientCertsModuleTask final : public CryptoTask {
@ -894,6 +842,8 @@ NS_IMETHODIMP
nsNSSComponent::HasUserCertsInstalled(bool* result) {
NS_ENSURE_ARG_POINTER(result);
BlockUntilLoadableCertsLoaded();
// FindClientCertificatesWithPrivateKeys won't ever return an empty list, so
// all we need to do is check if this is null or not.
UniqueCERTCertList certList(FindClientCertificatesWithPrivateKeys());
@ -992,7 +942,18 @@ static nsresult GetNSS3Directory(nsCString& result) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get parent directory?"));
return rv;
}
return FileToCString(nss3Directory, result);
#ifdef XP_WIN
// Native path will drop Unicode characters that cannot be mapped to system's
// codepage, using short (canonical) path as workaround.
nsCOMPtr<nsILocalFileWin> nss3DirectoryWin = do_QueryInterface(nss3Directory);
if (!nss3DirectoryWin) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("couldn't get nsILocalFileWin"));
return NS_ERROR_FAILURE;
}
return nss3DirectoryWin->GetNativeCanonicalPath(result);
#else
return nss3Directory->GetNativePath(result);
#endif
}
// The loadable roots library is probably in the same directory we loaded the
@ -2660,9 +2621,6 @@ UniqueCERTCertList FindClientCertificatesWithPrivateKeys() {
});
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("FindClientCertificatesWithPrivateKeys"));
BlockUntilLoadableCertsLoaded();
UniqueCERTCertList certsWithPrivateKeys(CERT_NewCertList());
if (!certsWithPrivateKeys) {
return nullptr;

Просмотреть файл

@ -25,12 +25,8 @@
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/net/SSLTokensCache.h"
#include "mozilla/net/SocketProcessChild.h"
#include "mozilla/psm/IPCClientCertsChild.h"
#include "mozilla/psm/PIPCClientCertsChild.h"
#include "mozpkix/pkixnss.h"
#include "mozpkix/pkixtypes.h"
#include "mozpkix/pkixutil.h"
@ -58,7 +54,6 @@
#include "sslproto.h"
using namespace mozilla::psm;
using namespace mozilla::ipc;
//#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
// reports when doing SSL read/write
@ -1831,7 +1826,8 @@ class ClientAuthDataRunnable : public SyncRunnableBase {
: mInfo(std::move(info)),
mServerCert(serverCert.get()),
mCollectedCANames(std::move(collectedCANames)),
mSelectedCertificate(nullptr) {}
mSelectedCertificate(nullptr),
mSelectedKey(nullptr) {}
virtual mozilla::pkix::Result BuildChainForCertificate(
CERTCertificate* cert, UniqueCERTCertList& builtChain);
@ -1841,6 +1837,10 @@ class ClientAuthDataRunnable : public SyncRunnableBase {
UniqueCERTCertificate TakeSelectedCertificate() {
return std::move(mSelectedCertificate);
}
// Take the private key for the selected certificate. Will be null if no
// certificate was selected or an error prevented selecting one or getting
// the corresponding key.
UniqueSECKEYPrivateKey TakeSelectedKey() { return std::move(mSelectedKey); }
protected:
virtual void RunOnTargetThread() override;
@ -1850,6 +1850,7 @@ class ClientAuthDataRunnable : public SyncRunnableBase {
nsTArray<nsTArray<uint8_t>> mCollectedCANames;
nsTArray<nsTArray<uint8_t>> mEnterpriseCertificates;
UniqueCERTCertificate mSelectedCertificate;
UniqueSECKEYPrivateKey mSelectedKey;
};
class RemoteClientAuthDataRunnable : public ClientAuthDataRunnable {
@ -1945,42 +1946,30 @@ SECStatus nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
nsTArray<nsTArray<uint8_t>> collectedCANames(CollectCANames(caNames));
UniqueCERTCertificate selectedCertificate;
UniqueSECKEYPrivateKey selectedKey;
UniqueCERTCertList builtChain;
SECStatus status = DoGetClientAuthData(std::move(authInfo), serverCert,
std::move(collectedCANames),
selectedCertificate, builtChain);
SECStatus status = DoGetClientAuthData(
std::move(authInfo), serverCert, std::move(collectedCANames),
selectedCertificate, selectedKey, builtChain);
if (status != SECSuccess) {
return status;
}
// Currently, the IPC client certs module only refreshes its view of
// available certificates and keys if the platform issues a search for all
// certificates or keys. In the socket process, such a search may not have
// happened, so this ensures it has.
if (XRE_IsSocketProcess()) {
UniqueCERTCertList certList(FindClientCertificatesWithPrivateKeys());
Unused << certList;
}
if (selectedCertificate) {
UniqueSECKEYPrivateKey selectedKey(
PK11_FindKeyByAnyCert(selectedCertificate.get(), nullptr));
if (selectedKey) {
if (builtChain) {
info->SetClientCertChain(std::move(builtChain));
} else {
MOZ_LOG(
gPIPNSSLog, LogLevel::Debug,
("[%p] couldn't determine chain for selected client cert", socket));
}
*pRetCert = selectedCertificate.release();
*pRetKey = selectedKey.release();
// Make joinConnection prohibit joining after we've sent a client cert
info->SetSentClientCert();
if (info->GetSSLVersionUsed() == nsISSLSocketControl::TLS_VERSION_1_3) {
Telemetry::Accumulate(Telemetry::TLS_1_3_CLIENT_AUTH_USES_PHA,
info->IsHandshakeCompleted());
}
if (selectedCertificate && selectedKey) {
if (builtChain) {
info->SetClientCertChain(std::move(builtChain));
} else {
MOZ_LOG(
gPIPNSSLog, LogLevel::Debug,
("[%p] couldn't determine chain for selected client cert", socket));
}
*pRetCert = selectedCertificate.release();
*pRetKey = selectedKey.release();
// Make joinConnection prohibit joining after we've sent a client cert
info->SetSentClientCert();
if (info->GetSSLVersionUsed() == nsISSLSocketControl::TLS_VERSION_1_3) {
Telemetry::Accumulate(Telemetry::TLS_1_3_CLIENT_AUTH_USES_PHA,
info->IsHandshakeCompleted());
}
}
@ -1991,6 +1980,7 @@ SECStatus DoGetClientAuthData(ClientAuthInfo&& info,
const UniqueCERTCertificate& serverCert,
nsTArray<nsTArray<uint8_t>>&& collectedCANames,
UniqueCERTCertificate& outCert,
UniqueSECKEYPrivateKey& outKey,
UniqueCERTCertList& outBuiltChain) {
// XXX: This should be done asynchronously; see bug 696976
RefPtr<ClientAuthDataRunnable> runnable =
@ -2007,7 +1997,8 @@ SECStatus DoGetClientAuthData(ClientAuthInfo&& info,
}
outCert = runnable->TakeSelectedCertificate();
if (outCert) {
outKey = runnable->TakeSelectedKey();
if (outCert && outKey) {
mozilla::pkix::Result result =
runnable->BuildChainForCertificate(outCert.get(), outBuiltChain);
if (result != Success) {
@ -2042,7 +2033,7 @@ class ClientAuthCertNonverifyingTrustDomain final : public TrustDomain {
virtual mozilla::pkix::Result CheckRevocation(
EndEntityOrCA endEntityOrCA, const CertID& certID, Time time,
mozilla::pkix::Duration validityDuration,
Duration validityDuration,
/*optional*/ const Input* stapledOCSPresponse,
/*optional*/ const Input* aiaExtension,
/*optional*/ const Input* sctExtension) override {
@ -2318,6 +2309,8 @@ void ClientAuthDataRunnable::RunOnTargetThread() {
if (NS_WARN_IF(!mSelectedCertificate)) {
return;
}
mSelectedKey.reset(
PK11_FindKeyByAnyCert(mSelectedCertificate.get(), nullptr));
return;
}
@ -2367,6 +2360,7 @@ void ClientAuthDataRunnable::RunOnTargetThread() {
} else {
// this is a good cert to present
mSelectedCertificate.reset(CERT_DupCertificate(node->cert));
mSelectedKey = std::move(tmpKey);
return;
}
}
@ -2378,6 +2372,8 @@ void ClientAuthDataRunnable::RunOnTargetThread() {
if (lowPrioNonrepCert) {
mSelectedCertificate = std::move(lowPrioNonrepCert);
mSelectedKey.reset(
PK11_FindKeyByAnyCert(mSelectedCertificate.get(), nullptr));
}
return;
}
@ -2426,6 +2422,8 @@ void ClientAuthDataRunnable::RunOnTargetThread() {
if (NS_WARN_IF(!mSelectedCertificate)) {
return;
}
mSelectedKey.reset(
PK11_FindKeyByAnyCert(mSelectedCertificate.get(), nullptr));
return;
}
}
@ -2487,6 +2485,8 @@ void ClientAuthDataRunnable::RunOnTargetThread() {
if (NS_WARN_IF(!mSelectedCertificate)) {
return;
}
mSelectedKey.reset(
PK11_FindKeyByAnyCert(mSelectedCertificate.get(), nullptr));
}
if (cars && wantRemember) {
@ -2550,19 +2550,18 @@ void RemoteClientAuthDataRunnable::RunOnTargetThread() {
bool succeeded = false;
ByteArray cert;
ByteArray key;
mozilla::net::SocketProcessChild::GetSingleton()->SendGetTLSClientCert(
nsCString(mInfo.HostName()), mInfo.OriginAttributesRef(), mInfo.Port(),
mInfo.ProviderFlags(), mInfo.ProviderTlsFlags(), serverCertSerialized,
clientCertSerialized, collectedCANames, &succeeded, &cert, &mBuiltChain);
clientCertSerialized, collectedCANames, &succeeded, &cert, &key,
&mBuiltChain);
if (!succeeded) {
return;
}
SECItem certItem = {siBuffer, const_cast<uint8_t*>(cert.data().Elements()),
static_cast<unsigned int>(cert.data().Length())};
mSelectedCertificate.reset(CERT_NewTempCertificate(
CERT_GetDefaultCertDB(), &certItem, nullptr, false, true));
DeserializeClientCertAndKey(cert, key, mSelectedCertificate, mSelectedKey);
}
static PRFileDesc* nsSSLIOLayerImportFD(PRFileDesc* fd,
@ -2949,91 +2948,3 @@ loser:
}
return NS_ERROR_FAILURE;
}
already_AddRefed<IPCClientCertsChild> GetIPCClientCertsActor() {
PBackgroundChild* backgroundActor =
BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread();
if (!backgroundActor) {
return nullptr;
}
RefPtr<PIPCClientCertsChild> actor =
SingleManagedOrNull(backgroundActor->ManagedPIPCClientCertsChild());
if (!actor) {
actor = backgroundActor->SendPIPCClientCertsConstructor(
new IPCClientCertsChild());
if (!actor) {
return nullptr;
}
}
return actor.forget().downcast<IPCClientCertsChild>();
}
extern "C" {
const uint8_t kIPCClientCertsObjectTypeCert = 1;
const uint8_t kIPCClientCertsObjectTypeRSAKey = 2;
const uint8_t kIPCClientCertsObjectTypeECKey = 3;
// This function is provided to the IPC client certs module so it can cause the
// parent process to find certificates and keys and send identifying
// information about them over IPC.
void DoFindObjects(FindObjectsCallback cb, void* ctx) {
RefPtr<IPCClientCertsChild> ipcClientCertsActor(GetIPCClientCertsActor());
if (!ipcClientCertsActor) {
return;
}
nsTArray<IPCClientCertObject> objects;
if (!ipcClientCertsActor->SendFindObjects(&objects)) {
return;
}
for (const auto& object : objects) {
switch (object.type()) {
case IPCClientCertObject::TECKey:
cb(kIPCClientCertsObjectTypeECKey, object.get_ECKey().params().Length(),
object.get_ECKey().params().Elements(),
object.get_ECKey().cert().Length(),
object.get_ECKey().cert().Elements(), object.get_ECKey().slotType(),
ctx);
break;
case IPCClientCertObject::TRSAKey:
cb(kIPCClientCertsObjectTypeRSAKey,
object.get_RSAKey().modulus().Length(),
object.get_RSAKey().modulus().Elements(),
object.get_RSAKey().cert().Length(),
object.get_RSAKey().cert().Elements(),
object.get_RSAKey().slotType(), ctx);
break;
case IPCClientCertObject::TCertificate:
cb(kIPCClientCertsObjectTypeCert,
object.get_Certificate().der().Length(),
object.get_Certificate().der().Elements(), 0, nullptr,
object.get_Certificate().slotType(), ctx);
break;
default:
MOZ_ASSERT_UNREACHABLE("unhandled IPCClientCertObject type");
break;
}
}
}
// This function is provided to the IPC client certs module so it can cause the
// parent process to sign the given data using the key corresponding to the
// given certificate, using the given parameters.
void DoSign(size_t cert_len, const uint8_t* cert, size_t data_len,
const uint8_t* data, size_t params_len, const uint8_t* params,
SignCallback cb, void* ctx) {
RefPtr<IPCClientCertsChild> ipcClientCertsActor(GetIPCClientCertsActor());
if (!ipcClientCertsActor) {
return;
}
ByteArray certBytes(nsTArray<uint8_t>(cert, cert_len));
ByteArray dataBytes(nsTArray<uint8_t>(data, data_len));
ByteArray paramsBytes(nsTArray<uint8_t>(params, params_len));
ByteArray signature;
if (!ipcClientCertsActor->SendSign(certBytes, dataBytes, paramsBytes,
&signature)) {
return;
}
cb(signature.data().Length(), signature.data().Elements(), ctx);
}
} // extern "C"

Просмотреть файл

@ -27,9 +27,6 @@ class SharedSSLState;
} // namespace psm
} // namespace mozilla
const uint32_t kIPCClientCertsSlotTypeModern = 1;
const uint32_t kIPCClientCertsSlotTypeLegacy = 2;
using mozilla::OriginAttributes;
class nsIObserver;
@ -357,22 +354,11 @@ nsresult nsSSLIOLayerAddToSocket(int32_t family, const char* host, int32_t port,
bool forSTARTTLS, uint32_t flags,
uint32_t tlsFlags);
extern "C" {
using FindObjectsCallback = void (*)(uint8_t type, size_t id_len,
const uint8_t* id, size_t data_len,
const uint8_t* data, uint32_t slotType,
void* ctx);
void DoFindObjects(FindObjectsCallback cb, void* ctx);
using SignCallback = void (*)(size_t data_len, const uint8_t* data, void* ctx);
void DoSign(size_t cert_len, const uint8_t* cert, size_t data_len,
const uint8_t* data, size_t params_len, const uint8_t* params,
SignCallback cb, void* ctx);
}
SECStatus DoGetClientAuthData(ClientAuthInfo&& info,
const mozilla::UniqueCERTCertificate& serverCert,
nsTArray<nsTArray<uint8_t>>&& collectedCANames,
mozilla::UniqueCERTCertificate& outCert,
mozilla::UniqueSECKEYPrivateKey& outKey,
mozilla::UniqueCERTCertList& outBuiltChain);
#endif // nsNSSIOLayer_h

Просмотреть файл

@ -88,7 +88,8 @@ macro_rules! manager_guard_to_manager {
// Helper macro to prefix log messages with the current thread ID.
macro_rules! log_with_thread_id {
($log_level:ident, $($message:expr),*) => {
$log_level!("{:?} {}", thread::current().id(), format_args!($($message),*));
let message = format!($($message),*);
$log_level!("{:?} {}", thread::current().id(), message);
};
}

Просмотреть файл

@ -146,7 +146,7 @@ impl ManagerProxy {
}
ManagerArguments::StartSearch(session, attrs) => {
ManagerReturnValue::StartSearch(
real_manager.start_search(session, attrs),
real_manager.start_search(session, &attrs),
)
}
ManagerArguments::Search(session, max_objects) => {
@ -167,11 +167,11 @@ impl ManagerProxy {
}
ManagerArguments::GetSignatureLength(session, data) => {
ManagerReturnValue::GetSignatureLength(
real_manager.get_signature_length(session, data),
real_manager.get_signature_length(session, &data),
)
}
ManagerArguments::Sign(session, data) => {
ManagerReturnValue::Sign(real_manager.sign(session, data))
ManagerReturnValue::Sign(real_manager.sign(session, &data))
}
ManagerArguments::Stop => ManagerReturnValue::Stop(Ok(())),
};
@ -402,23 +402,23 @@ impl<B: ClientCertsBackend> Object<B> {
fn get_signature_length(
&mut self,
data: Vec<u8>,
data: &[u8],
params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
) -> Result<usize, Error> {
match self {
Object::Cert(_) => Err(error_here!(ErrorType::InvalidArgument)),
Object::Key(key) => key.get_signature_length(&data, params),
Object::Key(key) => key.get_signature_length(data, params),
}
}
fn sign(
&mut self,
data: Vec<u8>,
data: &[u8],
params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
) -> Result<Vec<u8>, Error> {
match self {
Object::Cert(_) => Err(error_here!(ErrorType::InvalidArgument)),
Object::Key(key) => key.sign(&data, params),
Object::Key(key) => key.sign(data, params),
}
}
}
@ -426,7 +426,7 @@ impl<B: ClientCertsBackend> Object<B> {
/// The `Manager` keeps track of the state of this module with respect to the PKCS #11
/// specification. This includes what sessions are open, which search and sign operations are
/// ongoing, and what objects are known and by what handle.
pub struct Manager<B: ClientCertsBackend> {
struct Manager<B: ClientCertsBackend> {
/// A map of session to session type (modern or legacy). Sessions can be created (opened) and
/// later closed.
sessions: BTreeMap<CK_SESSION_HANDLE, SlotType>,
@ -546,7 +546,7 @@ impl<B: ClientCertsBackend> Manager<B> {
pub fn start_search(
&mut self,
session: CK_SESSION_HANDLE,
attrs: Vec<(CK_ATTRIBUTE_TYPE, Vec<u8>)>,
attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)],
) -> Result<(), Error> {
let slot_type = match self.sessions.get(&session) {
Some(slot_type) => *slot_type,
@ -554,7 +554,7 @@ impl<B: ClientCertsBackend> Manager<B> {
};
// If the search is for an attribute we don't support, no objects will match. This check
// saves us having to look through all of our objects.
for (attr, _) in &attrs {
for (attr, _) in attrs {
if !SUPPORTED_ATTRIBUTES.contains(attr) {
self.searches.insert(session, Vec::new());
return Ok(());
@ -565,12 +565,12 @@ impl<B: ClientCertsBackend> Manager<B> {
// indication for the backend to re-scan for new objects from tokens that may have been
// inserted or certificates that may have been imported into the OS. Since these searches
// are relatively rare, this minimizes the impact of doing these re-scans.
if search_is_for_all_certificates_or_keys(&attrs)? {
if search_is_for_all_certificates_or_keys(attrs)? {
self.maybe_find_new_objects()?;
}
let mut handles = Vec::new();
for (handle, object) in &self.objects {
if object.matches(slot_type, &attrs) {
if object.matches(slot_type, attrs) {
handles.push(*handle);
}
}
@ -651,7 +651,7 @@ impl<B: ClientCertsBackend> Manager<B> {
pub fn get_signature_length(
&mut self,
session: CK_SESSION_HANDLE,
data: Vec<u8>,
data: &[u8],
) -> Result<usize, Error> {
let (key_handle, params) = match self.signs.get(&session) {
Some((key_handle, params)) => (key_handle, params),
@ -664,7 +664,7 @@ impl<B: ClientCertsBackend> Manager<B> {
key.get_signature_length(data, params)
}
pub fn sign(&mut self, session: CK_SESSION_HANDLE, data: Vec<u8>) -> Result<Vec<u8>, Error> {
pub fn sign(&mut self, session: CK_SESSION_HANDLE, data: &[u8]) -> Result<Vec<u8>, Error> {
// Performing the signature (via C_Sign, which is the only way we support) finishes the sign
// operation, so it needs to be removed here.
let (key_handle, params) = match self.signs.remove(&session) {