зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
667224045f
Коммит
045a43b2c8
|
@ -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 ? ¶ms : 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) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче