diff --git a/Cargo.lock b/Cargo.lock index 04bed7f6ebc2..17c18eb28d31 100644 --- a/Cargo.lock +++ b/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" diff --git a/Cargo.toml b/Cargo.toml index bcaf38775125..bbe98176e4a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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", diff --git a/browser/components/extensions/parent/ext-pkcs11.js b/browser/components/extensions/parent/ext-pkcs11.js index 334adaa2c3ed..697cd85d2775 100644 --- a/browser/components/extensions/parent/ext-pkcs11.js +++ b/browser/components/extensions/parent/ext-pkcs11.js @@ -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; } diff --git a/browser/components/extensions/test/xpcshell/test_ext_pkcs11_management.js b/browser/components/extensions/test/xpcshell/test_ext_pkcs11_management.js index 6463c5964870..ffd510fe6543 100644 --- a/browser/components/extensions/test/xpcshell/test_ext_pkcs11_management.js +++ b/browser/components/extensions/test/xpcshell/test_ext_pkcs11_management.js @@ -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}`); diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 0d2ff9dff232..4d7a4810a7f2 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -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) diff --git a/dom/media/webrtc/transport/dtlsidentity.cpp b/dom/media/webrtc/transport/dtlsidentity.cpp index e4ecee321013..25e22d1c9744 100644 --- a/dom/media/webrtc/transport/dtlsidentity.cpp +++ b/dom/media/webrtc/transport/dtlsidentity.cpp @@ -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* aKeyDer, nsTArray* 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::Deserialize( static_cast(aKeyDer.Length())}; SECKEYPrivateKey* privateKey; - if (UnwrapPrivateKeyInfoWithEmptyPassword(&derPKI, cert, &privateKey) != + if (psm::UnwrapPrivateKeyInfoWithEmptyPassword(&derPKI, cert, &privateKey) != SECSuccess) { MOZ_ASSERT(false); return nullptr; diff --git a/ipc/glue/BackgroundChildImpl.cpp b/ipc/glue/BackgroundChildImpl.cpp index b3109d80306a..b86db05139f1 100644 --- a/ipc/glue/BackgroundChildImpl.cpp +++ b/ipc/glue/BackgroundChildImpl.cpp @@ -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" diff --git a/ipc/glue/BackgroundParentImpl.cpp b/ipc/glue/BackgroundParentImpl.cpp index 69c1a6a7c99e..ad8b460972cf 100644 --- a/ipc/glue/BackgroundParentImpl.cpp +++ b/ipc/glue/BackgroundParentImpl.cpp @@ -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 -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 result = new psm::IPCClientCertsParent(); - return result.forget(); -} - bool BackgroundParentImpl::DeallocPMessagePortParent( PMessagePortParent* aActor) { AssertIsInMainOrSocketProcess(); diff --git a/ipc/glue/BackgroundParentImpl.h b/ipc/glue/BackgroundParentImpl.h index f809ae382c89..3cf25b2357ae 100644 --- a/ipc/glue/BackgroundParentImpl.h +++ b/ipc/glue/BackgroundParentImpl.h @@ -293,8 +293,6 @@ class BackgroundParentImpl : public PBackgroundParent, PMessagePortParent* aActor, const nsID& aUUID, const nsID& aDestinationUUID, const uint32_t& aSequenceID) override; - already_AddRefed AllocPIPCClientCertsParent() override; - bool DeallocPMessagePortParent(PMessagePortParent* aActor) override; mozilla::ipc::IPCResult RecvMessagePortForceClose( diff --git a/ipc/glue/PBackground.ipdl b/ipc/glue/PBackground.ipdl index 03dbbb98a04b..019d6f0d9237 100644 --- a/ipc/glue/PBackground.ipdl +++ b/ipc/glue/PBackground.ipdl @@ -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(); diff --git a/ipc/ipdl/sync-messages.ini b/ipc/ipdl/sync-messages.ini index 9812691c1648..f3f322261856 100644 --- a/ipc/ipdl/sync-messages.ini +++ b/ipc/ipdl/sync-messages.ini @@ -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 # diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index 3149f3ac9c6b..95eaa5107f2f 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -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 diff --git a/netwerk/ipc/PSocketProcess.ipdl b/netwerk/ipc/PSocketProcess.ipdl index 2a332136c256..11988f4976e9 100644 --- a/netwerk/ipc/PSocketProcess.ipdl +++ b/netwerk/ipc/PSocketProcess.ipdl @@ -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, diff --git a/netwerk/ipc/SocketProcessChild.cpp b/netwerk/ipc/SocketProcessChild.cpp index ee4a73637241..e6ea9ea56b95 100644 --- a/netwerk/ipc/SocketProcessChild.cpp +++ b/netwerk/ipc/SocketProcessChild.cpp @@ -165,15 +165,7 @@ bool SocketProcessChild::Init(base::ProcessId aParentPid, // Initialize DNS Service here, since it needs to be done in main thread. nsCOMPtr 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(); } diff --git a/netwerk/ipc/SocketProcessImpl.cpp b/netwerk/ipc/SocketProcessImpl.cpp index 6a0739622f16..6f55eb85845f 100644 --- a/netwerk/ipc/SocketProcessImpl.cpp +++ b/netwerk/ipc/SocketProcessImpl.cpp @@ -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 diff --git a/netwerk/ipc/SocketProcessParent.cpp b/netwerk/ipc/SocketProcessParent.cpp index 6a69209be231..92f1fb2fc752 100644 --- a/netwerk/ipc/SocketProcessParent.cpp +++ b/netwerk/ipc/SocketProcessParent.cpp @@ -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&& aClientCert, nsTArray&& aCollectedCANames, - bool* aSucceeded, ByteArray* aOutCert, nsTArray* aBuiltChain) { + bool* aSucceeded, ByteArray* aOutCert, ByteArray* aOutKey, + nsTArray* 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); diff --git a/netwerk/ipc/SocketProcessParent.h b/netwerk/ipc/SocketProcessParent.h index 3628a0ee449d..c51124d991e8 100644 --- a/netwerk/ipc/SocketProcessParent.h +++ b/netwerk/ipc/SocketProcessParent.h @@ -99,14 +99,8 @@ class SocketProcessParent final const int32_t& aPort, const uint32_t& aProviderFlags, const uint32_t& aProviderTlsFlags, const ByteArray& aServerCert, Maybe&& aClientCert, nsTArray&& aCollectedCANames, - bool* aSucceeded, ByteArray* aOutCert, nsTArray* aBuiltChain); - - mozilla::ipc::IPCResult RecvFindIPCClientCertObjects( - nsTArray* aObjects); - mozilla::ipc::IPCResult RecvIPCClientCertSign(ByteArray aCert, - ByteArray aData, - ByteArray aParams, - ByteArray* aSignature); + bool* aSucceeded, ByteArray* aOutCert, ByteArray* aOutKey, + nsTArray* aBuiltChain); already_AddRefed AllocPProxyConfigLookupParent( nsIURI* aURI, const uint32_t& aProxyResolveFlags); diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index 7bded0536ace..bac3b6b874f7 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -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(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, diff --git a/security/certverifier/NSSCertDBTrustDomain.h b/security/certverifier/NSSCertDBTrustDomain.h index d79a52dbc4c0..c3ac82420c96 100644 --- a/security/certverifier/NSSCertDBTrustDomain.h +++ b/security/certverifier/NSSCertDBTrustDomain.h @@ -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); diff --git a/security/manager/ssl/IPCClientCertsChild.cpp b/security/manager/ssl/IPCClientCertsChild.cpp deleted file mode 100644 index bea0e27dffc7..000000000000 --- a/security/manager/ssl/IPCClientCertsChild.cpp +++ /dev/null @@ -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 diff --git a/security/manager/ssl/IPCClientCertsChild.h b/security/manager/ssl/IPCClientCertsChild.h deleted file mode 100644 index 17020fce2ed3..000000000000 --- a/security/manager/ssl/IPCClientCertsChild.h +++ /dev/null @@ -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 diff --git a/security/manager/ssl/IPCClientCertsParent.cpp b/security/manager/ssl/IPCClientCertsParent.cpp deleted file mode 100644 index 8058dbdd8365..000000000000 --- a/security/manager/ssl/IPCClientCertsParent.cpp +++ /dev/null @@ -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* aObjects) { - UniqueCERTCertList certList(psm::FindClientCertificatesWithPrivateKeys()); - if (!certList) { - return IPC_OK(); - } - CERTCertListNode* n = CERT_LIST_HEAD(certList); - while (!CERT_LIST_END(n, certList)) { - nsTArray 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 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 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(aCert.data().Elements()), - static_cast(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(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(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 diff --git a/security/manager/ssl/IPCClientCertsParent.h b/security/manager/ssl/IPCClientCertsParent.h deleted file mode 100644 index 09ad589aca05..000000000000 --- a/security/manager/ssl/IPCClientCertsParent.h +++ /dev/null @@ -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* aObjects); - mozilla::ipc::IPCResult RecvSign(ByteArray aCert, ByteArray aData, - ByteArray aParams, ByteArray* aSignature); - - private: - IPCClientCertsParent(); - ~IPCClientCertsParent() = default; -}; - -} // namespace psm -} // namespace mozilla - -#endif diff --git a/security/manager/ssl/PIPCClientCerts.ipdl b/security/manager/ssl/PIPCClientCerts.ipdl deleted file mode 100644 index 6e9d7bad61e5..000000000000 --- a/security/manager/ssl/PIPCClientCerts.ipdl +++ /dev/null @@ -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 diff --git a/security/manager/ssl/PSMIPCCommon.cpp b/security/manager/ssl/PSMIPCCommon.cpp index e69de29bb2d1..6e0ed62302b3 100644 --- a/security/manager/ssl/PSMIPCCommon.cpp +++ b/security/manager/ssl/PSMIPCCommon.cpp @@ -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(aSerializedCert.data().Elements()), + static_cast(aSerializedCert.data().Length())}; + + UniqueCERTCertificate cert(CERT_NewTempCertificate( + CERT_GetDefaultCertDB(), &item, nullptr, false, true)); + + if (!cert) { + return; + } + + SECItem derPKI = {siBuffer, + const_cast(aSerializedKey.data().Elements()), + static_cast(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 diff --git a/security/manager/ssl/PSMIPCCommon.h b/security/manager/ssl/PSMIPCCommon.h index e69de29bb2d1..7d5455dd4b3f 100644 --- a/security/manager/ssl/PSMIPCCommon.h +++ b/security/manager/ssl/PSMIPCCommon.h @@ -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__ diff --git a/security/manager/ssl/PSMIPCTypes.ipdlh b/security/manager/ssl/PSMIPCTypes.ipdlh index 54bce317c203..73e8ca04f525 100644 --- a/security/manager/ssl/PSMIPCTypes.ipdlh +++ b/security/manager/ssl/PSMIPCTypes.ipdlh @@ -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; diff --git a/security/manager/ssl/ipcclientcerts/Cargo.toml b/security/manager/ssl/ipcclientcerts/Cargo.toml deleted file mode 100644 index c9d8009d4d52..000000000000 --- a/security/manager/ssl/ipcclientcerts/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "ipcclientcerts-static" -version = "0.1.0" -authors = ["Dana Keeler "] -edition = "2018" - -[dependencies] -byteorder = "1.3" -once_cell = "1" -pkcs11 = "0.4" -rsclientcerts = { path = "../rsclientcerts" } -sha2 = "0.8" - -[lib] -crate-type = ["staticlib"] diff --git a/security/manager/ssl/ipcclientcerts/dynamic-library/ipcclientcerts.symbols b/security/manager/ssl/ipcclientcerts/dynamic-library/ipcclientcerts.symbols deleted file mode 100644 index 562ecea21d43..000000000000 --- a/security/manager/ssl/ipcclientcerts/dynamic-library/ipcclientcerts.symbols +++ /dev/null @@ -1 +0,0 @@ -C_GetFunctionList diff --git a/security/manager/ssl/ipcclientcerts/dynamic-library/moz.build b/security/manager/ssl/ipcclientcerts/dynamic-library/moz.build deleted file mode 100644 index 57c1f919cef4..000000000000 --- a/security/manager/ssl/ipcclientcerts/dynamic-library/moz.build +++ /dev/null @@ -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" diff --git a/security/manager/ssl/ipcclientcerts/dynamic-library/stub.c b/security/manager/ssl/ipcclientcerts/dynamic-library/stub.c deleted file mode 100644 index 3263799e391e..000000000000 --- a/security/manager/ssl/ipcclientcerts/dynamic-library/stub.c +++ /dev/null @@ -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); -} diff --git a/security/manager/ssl/ipcclientcerts/dynamic-library/stub.cpp b/security/manager/ssl/ipcclientcerts/dynamic-library/stub.cpp deleted file mode 100644 index e50f8675741d..000000000000 --- a/security/manager/ssl/ipcclientcerts/dynamic-library/stub.cpp +++ /dev/null @@ -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); -} -} diff --git a/security/manager/ssl/ipcclientcerts/moz.build b/security/manager/ssl/ipcclientcerts/moz.build deleted file mode 100644 index 1d24bdea31da..000000000000 --- a/security/manager/ssl/ipcclientcerts/moz.build +++ /dev/null @@ -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") diff --git a/security/manager/ssl/ipcclientcerts/src/backend.rs b/security/manager/ssl/ipcclientcerts/src/backend.rs deleted file mode 100644 index d6c17864f37b..000000000000 --- a/security/manager/ssl/ipcclientcerts/src/backend.rs +++ /dev/null @@ -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, - token: Vec, - id: Vec, - label: Vec, - value: Vec, - issuer: Vec, - serial_number: Vec, - subject: Vec, - slot_type: SlotType, -} - -impl Cert { - fn new(der: &[u8], slot_type: SlotType) -> Result { - 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)]) -> 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, - class: Vec, - token: Vec, - id: Vec, - private: Vec, - key_type: Vec, - modulus: Option>, - ec_params: Option>, - slot_type: SlotType, - sign: SignFunction, -} - -impl Key { - fn new( - modulus: Option<&[u8]>, - ec_params: Option<&[u8]>, - cert: &[u8], - slot_type: SlotType, - sign: SignFunction, - ) -> Result { - 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)]) -> 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, - ) -> Result { - // 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, - ) -> Result, Error> { - let mut signature = Vec::new(); - let (params_len, params) = match params { - Some(params) => ( - std::mem::size_of::(), - 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 = 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, - keys: Vec, - 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, Vec), 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)) - } -} diff --git a/security/manager/ssl/ipcclientcerts/src/lib.rs b/security/manager/ssl/ipcclientcerts/src/lib.rs deleted file mode 100644 index 43b284bf90d8..000000000000 --- a/security/manager/ssl/ipcclientcerts/src/lib.rs +++ /dev/null @@ -1,1048 +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/. */ - -#![allow(non_snake_case)] - -extern crate byteorder; -extern crate once_cell; -extern crate pkcs11; -#[macro_use] -extern crate rsclientcerts; -extern crate sha2; - -use once_cell::sync::OnceCell; -use pkcs11::types::*; -use rsclientcerts::manager::{Manager, SlotType}; -use std::ffi::{c_void, CStr}; -use std::sync::Mutex; - -mod backend; - -use backend::Backend; - -type FindObjectsCallback = Option< - unsafe extern "C" fn( - typ: u8, - data_len: usize, - data: *const u8, - extra_len: usize, - extra: *const u8, - slot_type: u32, - ctx: *mut c_void, - ), ->; - -type FindObjectsFunction = extern "C" fn(callback: FindObjectsCallback, ctx: *mut c_void); - -type SignCallback = - Option; - -type SignFunction = extern "C" fn( - cert_len: usize, - cert: *const u8, - data_len: usize, - data: *const u8, - params_len: usize, - params: *const u8, - callback: SignCallback, - ctx: *mut c_void, -); - -/// The singleton `Manager` that handles state with respect to PKCS #11. Only one thread -/// may use it at a time, but there is no restriction on which threads may use it. -static mut MANAGER: OnceCell>>> = OnceCell::new(); - -// Obtaining a handle on the manager is a two-step process. First the mutex must be locked, which -// (if successful), results in a mutex guard object. We must then get a mutable refence to the -// underlying manager (if set - otherwise we return an error). This can't happen all in one macro -// without dropping a reference that needs to live long enough for this to be safe. In -// practice, this looks like: -// let mut manager_guard = try_to_get_manager_guard!(); -// let manager = manager_guard_to_manager!(manager_guard); -macro_rules! try_to_get_manager_guard { - () => { - unsafe { - match MANAGER.get_or_init(|| Mutex::new(None)).lock() { - Ok(maybe_manager) => maybe_manager, - Err(_) => return CKR_DEVICE_ERROR, - } - } - }; -} - -macro_rules! manager_guard_to_manager { - ($manager_guard:ident) => { - match $manager_guard.as_mut() { - Some(manager) => manager, - None => return CKR_DEVICE_ERROR, - } - }; -} - -/// This gets called to initialize the module. For this implementation, this consists of -/// instantiating the `Manager`. -extern "C" fn C_Initialize(pInitArgs: CK_C_INITIALIZE_ARGS_PTR) -> CK_RV { - // pInitArgs.pReserved will be a c-string containing the base-16 - // stringification of the addresses of the functions to call to communicate - // with the main process. - if pInitArgs.is_null() { - return CKR_DEVICE_ERROR; - } - let serialized_addresses_ptr = unsafe { (*pInitArgs).pReserved }; - if serialized_addresses_ptr.is_null() { - return CKR_DEVICE_ERROR; - } - let serialized_addresses_cstr = - unsafe { CStr::from_ptr(serialized_addresses_ptr as *mut std::os::raw::c_char) }; - let serialized_addresses = match serialized_addresses_cstr.to_str() { - Ok(serialized_addresses) => serialized_addresses, - Err(_) => return CKR_DEVICE_ERROR, - }; - let function_addresses: Vec = serialized_addresses - .split(',') - .filter_map(|serialized_address| usize::from_str_radix(serialized_address, 16).ok()) - .collect(); - if function_addresses.len() != 2 { - return CKR_DEVICE_ERROR; - } - let find_objects: FindObjectsFunction = unsafe { std::mem::transmute(function_addresses[0]) }; - let sign: SignFunction = unsafe { std::mem::transmute(function_addresses[1]) }; - let mut manager_guard = try_to_get_manager_guard!(); - let _unexpected_previous_manager = - manager_guard.replace(Manager::new(Backend::new(find_objects, sign))); - CKR_OK -} - -extern "C" fn C_Finalize(_pReserved: CK_VOID_PTR) -> CK_RV { - // Drop the manager. When C_Finalize is called, there should be only one - // reference to this module (which is going away), so there shouldn't be - // any concurrency issues. - let _ = unsafe { MANAGER.take() }; - CKR_OK -} - -// The specification mandates that these strings be padded with spaces to the appropriate length. -// Since the length of fixed-size arrays in rust is part of the type, the compiler enforces that -// these byte strings are of the correct length. -const MANUFACTURER_ID_BYTES: &[u8; 32] = b"Mozilla Corporation "; -const LIBRARY_DESCRIPTION_BYTES: &[u8; 32] = b"IPC Client Cert Module "; - -/// This gets called to gather some information about the module. In particular, this implementation -/// supports (portions of) cryptoki (PKCS #11) version 2.2. -extern "C" fn C_GetInfo(pInfo: CK_INFO_PTR) -> CK_RV { - if pInfo.is_null() { - return CKR_ARGUMENTS_BAD; - } - let mut info = CK_INFO::default(); - info.cryptokiVersion.major = 2; - info.cryptokiVersion.minor = 2; - info.manufacturerID = *MANUFACTURER_ID_BYTES; - info.libraryDescription = *LIBRARY_DESCRIPTION_BYTES; - unsafe { - *pInfo = info; - } - CKR_OK -} - -/// This module has two slots. -const SLOT_COUNT: CK_ULONG = 2; -/// The slot with ID 1 supports modern mechanisms like RSA-PSS. -const SLOT_ID_MODERN: CK_SLOT_ID = 1; -/// The slot with ID 2 only supports legacy mechanisms. -const SLOT_ID_LEGACY: CK_SLOT_ID = 2; - -/// This gets called twice: once with a null `pSlotList` to get the number of slots (returned via -/// `pulCount`) and a second time to get the ID for each slot. -extern "C" fn C_GetSlotList( - _tokenPresent: CK_BBOOL, - pSlotList: CK_SLOT_ID_PTR, - pulCount: CK_ULONG_PTR, -) -> CK_RV { - if pulCount.is_null() { - return CKR_ARGUMENTS_BAD; - } - if !pSlotList.is_null() { - if unsafe { *pulCount } < SLOT_COUNT { - return CKR_BUFFER_TOO_SMALL; - } - unsafe { - *pSlotList = SLOT_ID_MODERN; - *pSlotList.offset(1) = SLOT_ID_LEGACY; - } - }; - unsafe { - *pulCount = SLOT_COUNT; - } - CKR_OK -} - -const SLOT_DESCRIPTION_MODERN_BYTES: &[u8; 64] = - b"IPC Client Cert Slot (Modern) "; -const SLOT_DESCRIPTION_LEGACY_BYTES: &[u8; 64] = - b"IPC Client Cert Slot (Legacy) "; - -/// This gets called to obtain information about slots. In this implementation, the tokens are -/// always present in the slots. -extern "C" fn C_GetSlotInfo(slotID: CK_SLOT_ID, pInfo: CK_SLOT_INFO_PTR) -> CK_RV { - if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pInfo.is_null() { - return CKR_ARGUMENTS_BAD; - } - let description = if slotID == SLOT_ID_MODERN { - SLOT_DESCRIPTION_MODERN_BYTES - } else { - SLOT_DESCRIPTION_LEGACY_BYTES - }; - let slot_info = CK_SLOT_INFO { - slotDescription: *description, - manufacturerID: *MANUFACTURER_ID_BYTES, - flags: CKF_TOKEN_PRESENT, - hardwareVersion: CK_VERSION::default(), - firmwareVersion: CK_VERSION::default(), - }; - unsafe { - *pInfo = slot_info; - } - CKR_OK -} - -const TOKEN_LABEL_MODERN_BYTES: &[u8; 32] = b"IPC Client Cert Token (Modern) "; -const TOKEN_LABEL_LEGACY_BYTES: &[u8; 32] = b"IPC Client Cert Token (Legacy) "; -const TOKEN_MODEL_BYTES: &[u8; 16] = b"ipcclientcerts "; -const TOKEN_SERIAL_NUMBER_BYTES: &[u8; 16] = b"0000000000000000"; - -/// This gets called to obtain some information about tokens. This implementation has two slots, -/// so it has two tokens. This information is primarily for display purposes. -extern "C" fn C_GetTokenInfo(slotID: CK_SLOT_ID, pInfo: CK_TOKEN_INFO_PTR) -> CK_RV { - if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pInfo.is_null() { - return CKR_ARGUMENTS_BAD; - } - let mut token_info = CK_TOKEN_INFO::default(); - let label = if slotID == SLOT_ID_MODERN { - TOKEN_LABEL_MODERN_BYTES - } else { - TOKEN_LABEL_LEGACY_BYTES - }; - token_info.label = *label; - token_info.manufacturerID = *MANUFACTURER_ID_BYTES; - token_info.model = *TOKEN_MODEL_BYTES; - token_info.serialNumber = *TOKEN_SERIAL_NUMBER_BYTES; - unsafe { - *pInfo = token_info; - } - CKR_OK -} - -/// This gets called to determine what mechanisms a slot supports. The modern slot supports ECDSA, -/// RSA PKCS, and RSA PSS. The legacy slot only supports RSA PKCS. -extern "C" fn C_GetMechanismList( - slotID: CK_SLOT_ID, - pMechanismList: CK_MECHANISM_TYPE_PTR, - pulCount: CK_ULONG_PTR, -) -> CK_RV { - if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pulCount.is_null() { - return CKR_ARGUMENTS_BAD; - } - let mechanisms = if slotID == SLOT_ID_MODERN { - vec![CKM_ECDSA, CKM_RSA_PKCS, CKM_RSA_PKCS_PSS] - } else { - vec![CKM_RSA_PKCS] - }; - if !pMechanismList.is_null() { - if unsafe { *pulCount as usize } < mechanisms.len() { - return CKR_ARGUMENTS_BAD; - } - for i in 0..mechanisms.len() { - unsafe { - *pMechanismList.offset(i as isize) = mechanisms[i]; - } - } - } - unsafe { - *pulCount = mechanisms.len() as CK_ULONG; - } - CKR_OK -} - -extern "C" fn C_GetMechanismInfo( - _slotID: CK_SLOT_ID, - _type: CK_MECHANISM_TYPE, - _pInfo: CK_MECHANISM_INFO_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_InitToken( - _slotID: CK_SLOT_ID, - _pPin: CK_UTF8CHAR_PTR, - _ulPinLen: CK_ULONG, - _pLabel: CK_UTF8CHAR_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_InitPIN( - _hSession: CK_SESSION_HANDLE, - _pPin: CK_UTF8CHAR_PTR, - _ulPinLen: CK_ULONG, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_SetPIN( - _hSession: CK_SESSION_HANDLE, - _pOldPin: CK_UTF8CHAR_PTR, - _ulOldLen: CK_ULONG, - _pNewPin: CK_UTF8CHAR_PTR, - _ulNewLen: CK_ULONG, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -/// This gets called to create a new session. This module defers to the `ManagerProxy` to implement -/// this. -extern "C" fn C_OpenSession( - slotID: CK_SLOT_ID, - _flags: CK_FLAGS, - _pApplication: CK_VOID_PTR, - _Notify: CK_NOTIFY, - phSession: CK_SESSION_HANDLE_PTR, -) -> CK_RV { - if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || phSession.is_null() { - return CKR_ARGUMENTS_BAD; - } - let mut manager_guard = try_to_get_manager_guard!(); - let manager = manager_guard_to_manager!(manager_guard); - let slot_type = if slotID == SLOT_ID_MODERN { - SlotType::Modern - } else { - SlotType::Legacy - }; - let session_handle = match manager.open_session(slot_type) { - Ok(session_handle) => session_handle, - Err(_) => return CKR_DEVICE_ERROR, - }; - unsafe { - *phSession = session_handle; - } - CKR_OK -} - -/// This gets called to close a session. This is handled by the `ManagerProxy`. -extern "C" fn C_CloseSession(hSession: CK_SESSION_HANDLE) -> CK_RV { - let mut manager_guard = try_to_get_manager_guard!(); - let manager = manager_guard_to_manager!(manager_guard); - if manager.close_session(hSession).is_err() { - return CKR_SESSION_HANDLE_INVALID; - } - CKR_OK -} - -/// This gets called to close all open sessions at once. This is handled by the `ManagerProxy`. -extern "C" fn C_CloseAllSessions(slotID: CK_SLOT_ID) -> CK_RV { - if slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY { - return CKR_ARGUMENTS_BAD; - } - let mut manager_guard = try_to_get_manager_guard!(); - let manager = manager_guard_to_manager!(manager_guard); - let slot_type = if slotID == SLOT_ID_MODERN { - SlotType::Modern - } else { - SlotType::Legacy - }; - match manager.close_all_sessions(slot_type) { - Ok(()) => CKR_OK, - Err(_) => CKR_DEVICE_ERROR, - } -} - -extern "C" fn C_GetSessionInfo(_hSession: CK_SESSION_HANDLE, _pInfo: CK_SESSION_INFO_PTR) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_GetOperationState( - _hSession: CK_SESSION_HANDLE, - _pOperationState: CK_BYTE_PTR, - _pulOperationStateLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_SetOperationState( - _hSession: CK_SESSION_HANDLE, - _pOperationState: CK_BYTE_PTR, - _ulOperationStateLen: CK_ULONG, - _hEncryptionKey: CK_OBJECT_HANDLE, - _hAuthenticationKey: CK_OBJECT_HANDLE, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_Login( - _hSession: CK_SESSION_HANDLE, - _userType: CK_USER_TYPE, - _pPin: CK_UTF8CHAR_PTR, - _ulPinLen: CK_ULONG, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -/// This gets called to log out and drop any authenticated resources. Because this module does not -/// hold on to authenticated resources, this module "implements" this by doing nothing and -/// returning a success result. -extern "C" fn C_Logout(_hSession: CK_SESSION_HANDLE) -> CK_RV { - CKR_OK -} - -extern "C" fn C_CreateObject( - _hSession: CK_SESSION_HANDLE, - _pTemplate: CK_ATTRIBUTE_PTR, - _ulCount: CK_ULONG, - _phObject: CK_OBJECT_HANDLE_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_CopyObject( - _hSession: CK_SESSION_HANDLE, - _hObject: CK_OBJECT_HANDLE, - _pTemplate: CK_ATTRIBUTE_PTR, - _ulCount: CK_ULONG, - _phNewObject: CK_OBJECT_HANDLE_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DestroyObject(_hSession: CK_SESSION_HANDLE, _hObject: CK_OBJECT_HANDLE) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_GetObjectSize( - _hSession: CK_SESSION_HANDLE, - _hObject: CK_OBJECT_HANDLE, - _pulSize: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -/// This gets called to obtain the values of a number of attributes of an object identified by the -/// given handle. This module implements this by requesting that the `ManagerProxy` find the object -/// and attempt to get the value of each attribute. If a specified attribute is not defined on the -/// object, the length of that attribute is set to -1 to indicate that it is not available. -/// This gets called twice: once to obtain the lengths of the attributes and again to get the -/// values. -extern "C" fn C_GetAttributeValue( - _hSession: CK_SESSION_HANDLE, - hObject: CK_OBJECT_HANDLE, - pTemplate: CK_ATTRIBUTE_PTR, - ulCount: CK_ULONG, -) -> CK_RV { - if pTemplate.is_null() { - return CKR_ARGUMENTS_BAD; - } - let mut attr_types = Vec::with_capacity(ulCount as usize); - for i in 0..ulCount { - let attr = unsafe { &*pTemplate.offset(i as isize) }; - attr_types.push(attr.attrType); - } - let mut manager_guard = try_to_get_manager_guard!(); - let manager = manager_guard_to_manager!(manager_guard); - let values = match manager.get_attributes(hObject, attr_types) { - Ok(values) => values, - Err(_) => return CKR_ARGUMENTS_BAD, - }; - if values.len() != ulCount as usize { - return CKR_DEVICE_ERROR; - } - for i in 0..ulCount as usize { - let mut attr = unsafe { &mut *pTemplate.offset(i as isize) }; - // NB: the safety of this array access depends on the length check above - if let Some(attr_value) = &values[i] { - if attr.pValue.is_null() { - attr.ulValueLen = attr_value.len() as CK_ULONG; - } else { - let ptr: *mut u8 = attr.pValue as *mut u8; - if attr_value.len() != attr.ulValueLen as usize { - return CKR_ARGUMENTS_BAD; - } - unsafe { - std::ptr::copy_nonoverlapping(attr_value.as_ptr(), ptr, attr_value.len()); - } - } - } else { - attr.ulValueLen = (0 - 1) as CK_ULONG; - } - } - CKR_OK -} - -extern "C" fn C_SetAttributeValue( - _hSession: CK_SESSION_HANDLE, - _hObject: CK_OBJECT_HANDLE, - _pTemplate: CK_ATTRIBUTE_PTR, - _ulCount: CK_ULONG, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -/// This gets called to initialize a search for objects matching a given list of attributes. This -/// module implements this by gathering the attributes and passing them to the `ManagerProxy` to -/// start the search. -extern "C" fn C_FindObjectsInit( - hSession: CK_SESSION_HANDLE, - pTemplate: CK_ATTRIBUTE_PTR, - ulCount: CK_ULONG, -) -> CK_RV { - if pTemplate.is_null() { - return CKR_ARGUMENTS_BAD; - } - let mut attrs = Vec::new(); - for i in 0..ulCount { - let attr = unsafe { &*pTemplate.offset(i as isize) }; - let slice = unsafe { - std::slice::from_raw_parts(attr.pValue as *const u8, attr.ulValueLen as usize) - }; - attrs.push((attr.attrType, slice.to_owned())); - } - let mut manager_guard = try_to_get_manager_guard!(); - let manager = manager_guard_to_manager!(manager_guard); - match manager.start_search(hSession, attrs) { - Ok(()) => {} - Err(_) => return CKR_ARGUMENTS_BAD, - } - CKR_OK -} - -/// This gets called after `C_FindObjectsInit` to get the results of a search. This module -/// implements this by looking up the search in the `ManagerProxy` and copying out the matching -/// object handles. -extern "C" fn C_FindObjects( - hSession: CK_SESSION_HANDLE, - phObject: CK_OBJECT_HANDLE_PTR, - ulMaxObjectCount: CK_ULONG, - pulObjectCount: CK_ULONG_PTR, -) -> CK_RV { - if phObject.is_null() || pulObjectCount.is_null() || ulMaxObjectCount == 0 { - return CKR_ARGUMENTS_BAD; - } - let mut manager_guard = try_to_get_manager_guard!(); - let manager = manager_guard_to_manager!(manager_guard); - let handles = match manager.search(hSession, ulMaxObjectCount as usize) { - Ok(handles) => handles, - Err(_) => return CKR_ARGUMENTS_BAD, - }; - if handles.len() > ulMaxObjectCount as usize { - return CKR_DEVICE_ERROR; - } - unsafe { - *pulObjectCount = handles.len() as CK_ULONG; - } - for (index, handle) in handles.iter().enumerate() { - if index < ulMaxObjectCount as usize { - unsafe { - *(phObject.add(index)) = *handle; - } - } - } - CKR_OK -} - -/// This gets called after `C_FindObjectsInit` and `C_FindObjects` to finish a search. The module -/// tells the `ManagerProxy` to clear the search. -extern "C" fn C_FindObjectsFinal(hSession: CK_SESSION_HANDLE) -> CK_RV { - let mut manager_guard = try_to_get_manager_guard!(); - let manager = manager_guard_to_manager!(manager_guard); - // It would be an error if there were no search for this session, but we can be permissive here. - match manager.clear_search(hSession) { - Ok(()) => CKR_OK, - Err(_) => CKR_DEVICE_ERROR, - } -} - -extern "C" fn C_EncryptInit( - _hSession: CK_SESSION_HANDLE, - _pMechanism: CK_MECHANISM_PTR, - _hKey: CK_OBJECT_HANDLE, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_Encrypt( - _hSession: CK_SESSION_HANDLE, - _pData: CK_BYTE_PTR, - _ulDataLen: CK_ULONG, - _pEncryptedData: CK_BYTE_PTR, - _pulEncryptedDataLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_EncryptUpdate( - _hSession: CK_SESSION_HANDLE, - _pPart: CK_BYTE_PTR, - _ulPartLen: CK_ULONG, - _pEncryptedPart: CK_BYTE_PTR, - _pulEncryptedPartLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_EncryptFinal( - _hSession: CK_SESSION_HANDLE, - _pLastEncryptedPart: CK_BYTE_PTR, - _pulLastEncryptedPartLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DecryptInit( - _hSession: CK_SESSION_HANDLE, - _pMechanism: CK_MECHANISM_PTR, - _hKey: CK_OBJECT_HANDLE, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_Decrypt( - _hSession: CK_SESSION_HANDLE, - _pEncryptedData: CK_BYTE_PTR, - _ulEncryptedDataLen: CK_ULONG, - _pData: CK_BYTE_PTR, - _pulDataLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DecryptUpdate( - _hSession: CK_SESSION_HANDLE, - _pEncryptedPart: CK_BYTE_PTR, - _ulEncryptedPartLen: CK_ULONG, - _pPart: CK_BYTE_PTR, - _pulPartLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DecryptFinal( - _hSession: CK_SESSION_HANDLE, - _pLastPart: CK_BYTE_PTR, - _pulLastPartLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DigestInit(_hSession: CK_SESSION_HANDLE, _pMechanism: CK_MECHANISM_PTR) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_Digest( - _hSession: CK_SESSION_HANDLE, - _pData: CK_BYTE_PTR, - _ulDataLen: CK_ULONG, - _pDigest: CK_BYTE_PTR, - _pulDigestLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DigestUpdate( - _hSession: CK_SESSION_HANDLE, - _pPart: CK_BYTE_PTR, - _ulPartLen: CK_ULONG, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DigestKey(_hSession: CK_SESSION_HANDLE, _hKey: CK_OBJECT_HANDLE) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DigestFinal( - _hSession: CK_SESSION_HANDLE, - _pDigest: CK_BYTE_PTR, - _pulDigestLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -/// This gets called to set up a sign operation. The module essentially defers to the -/// `ManagerProxy`. -extern "C" fn C_SignInit( - hSession: CK_SESSION_HANDLE, - pMechanism: CK_MECHANISM_PTR, - hKey: CK_OBJECT_HANDLE, -) -> CK_RV { - if pMechanism.is_null() { - return CKR_ARGUMENTS_BAD; - } - // Presumably we should validate the mechanism against hKey, but the specification doesn't - // actually seem to require this. - let mechanism = unsafe { *pMechanism }; - let mechanism_params = if mechanism.mechanism == CKM_RSA_PKCS_PSS { - if mechanism.ulParameterLen as usize != std::mem::size_of::() { - return CKR_ARGUMENTS_BAD; - } - Some(unsafe { *(mechanism.pParameter as *const CK_RSA_PKCS_PSS_PARAMS) }) - } else { - None - }; - let mut manager_guard = try_to_get_manager_guard!(); - let manager = manager_guard_to_manager!(manager_guard); - match manager.start_sign(hSession, hKey, mechanism_params) { - Ok(()) => {} - Err(_) => return CKR_GENERAL_ERROR, - }; - CKR_OK -} - -/// NSS calls this after `C_SignInit` (there are more ways in the PKCS #11 specification to sign -/// data, but this is the only way supported by this module). The module essentially defers to the -/// `ManagerProxy` and copies out the resulting signature. -extern "C" fn C_Sign( - hSession: CK_SESSION_HANDLE, - pData: CK_BYTE_PTR, - ulDataLen: CK_ULONG, - pSignature: CK_BYTE_PTR, - pulSignatureLen: CK_ULONG_PTR, -) -> CK_RV { - if pData.is_null() || pulSignatureLen.is_null() { - return CKR_ARGUMENTS_BAD; - } - let data = unsafe { std::slice::from_raw_parts(pData, ulDataLen as usize) }; - if pSignature.is_null() { - let mut manager_guard = try_to_get_manager_guard!(); - let manager = manager_guard_to_manager!(manager_guard); - match manager.get_signature_length(hSession, data.to_vec()) { - Ok(signature_length) => unsafe { - *pulSignatureLen = signature_length as CK_ULONG; - }, - Err(_) => return CKR_GENERAL_ERROR, - } - } else { - let mut manager_guard = try_to_get_manager_guard!(); - let manager = manager_guard_to_manager!(manager_guard); - match manager.sign(hSession, data.to_vec()) { - Ok(signature) => { - let signature_capacity = unsafe { *pulSignatureLen } as usize; - if signature_capacity < signature.len() { - return CKR_ARGUMENTS_BAD; - } - let ptr: *mut u8 = pSignature as *mut u8; - unsafe { - std::ptr::copy_nonoverlapping(signature.as_ptr(), ptr, signature.len()); - *pulSignatureLen = signature.len() as CK_ULONG; - } - } - Err(_) => return CKR_GENERAL_ERROR, - } - } - CKR_OK -} - -extern "C" fn C_SignUpdate( - _hSession: CK_SESSION_HANDLE, - _pPart: CK_BYTE_PTR, - _ulPartLen: CK_ULONG, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_SignFinal( - _hSession: CK_SESSION_HANDLE, - _pSignature: CK_BYTE_PTR, - _pulSignatureLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_SignRecoverInit( - _hSession: CK_SESSION_HANDLE, - _pMechanism: CK_MECHANISM_PTR, - _hKey: CK_OBJECT_HANDLE, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_SignRecover( - _hSession: CK_SESSION_HANDLE, - _pData: CK_BYTE_PTR, - _ulDataLen: CK_ULONG, - _pSignature: CK_BYTE_PTR, - _pulSignatureLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_VerifyInit( - _hSession: CK_SESSION_HANDLE, - _pMechanism: CK_MECHANISM_PTR, - _hKey: CK_OBJECT_HANDLE, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_Verify( - _hSession: CK_SESSION_HANDLE, - _pData: CK_BYTE_PTR, - _ulDataLen: CK_ULONG, - _pSignature: CK_BYTE_PTR, - _ulSignatureLen: CK_ULONG, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_VerifyUpdate( - _hSession: CK_SESSION_HANDLE, - _pPart: CK_BYTE_PTR, - _ulPartLen: CK_ULONG, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_VerifyFinal( - _hSession: CK_SESSION_HANDLE, - _pSignature: CK_BYTE_PTR, - _ulSignatureLen: CK_ULONG, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_VerifyRecoverInit( - _hSession: CK_SESSION_HANDLE, - _pMechanism: CK_MECHANISM_PTR, - _hKey: CK_OBJECT_HANDLE, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_VerifyRecover( - _hSession: CK_SESSION_HANDLE, - _pSignature: CK_BYTE_PTR, - _ulSignatureLen: CK_ULONG, - _pData: CK_BYTE_PTR, - _pulDataLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DigestEncryptUpdate( - _hSession: CK_SESSION_HANDLE, - _pPart: CK_BYTE_PTR, - _ulPartLen: CK_ULONG, - _pEncryptedPart: CK_BYTE_PTR, - _pulEncryptedPartLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DecryptDigestUpdate( - _hSession: CK_SESSION_HANDLE, - _pEncryptedPart: CK_BYTE_PTR, - _ulEncryptedPartLen: CK_ULONG, - _pPart: CK_BYTE_PTR, - _pulPartLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_SignEncryptUpdate( - _hSession: CK_SESSION_HANDLE, - _pPart: CK_BYTE_PTR, - _ulPartLen: CK_ULONG, - _pEncryptedPart: CK_BYTE_PTR, - _pulEncryptedPartLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DecryptVerifyUpdate( - _hSession: CK_SESSION_HANDLE, - _pEncryptedPart: CK_BYTE_PTR, - _ulEncryptedPartLen: CK_ULONG, - _pPart: CK_BYTE_PTR, - _pulPartLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_GenerateKey( - _hSession: CK_SESSION_HANDLE, - _pMechanism: CK_MECHANISM_PTR, - _pTemplate: CK_ATTRIBUTE_PTR, - _ulCount: CK_ULONG, - _phKey: CK_OBJECT_HANDLE_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_GenerateKeyPair( - _hSession: CK_SESSION_HANDLE, - _pMechanism: CK_MECHANISM_PTR, - _pPublicKeyTemplate: CK_ATTRIBUTE_PTR, - _ulPublicKeyAttributeCount: CK_ULONG, - _pPrivateKeyTemplate: CK_ATTRIBUTE_PTR, - _ulPrivateKeyAttributeCount: CK_ULONG, - _phPublicKey: CK_OBJECT_HANDLE_PTR, - _phPrivateKey: CK_OBJECT_HANDLE_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_WrapKey( - _hSession: CK_SESSION_HANDLE, - _pMechanism: CK_MECHANISM_PTR, - _hWrappingKey: CK_OBJECT_HANDLE, - _hKey: CK_OBJECT_HANDLE, - _pWrappedKey: CK_BYTE_PTR, - _pulWrappedKeyLen: CK_ULONG_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_UnwrapKey( - _hSession: CK_SESSION_HANDLE, - _pMechanism: CK_MECHANISM_PTR, - _hUnwrappingKey: CK_OBJECT_HANDLE, - _pWrappedKey: CK_BYTE_PTR, - _ulWrappedKeyLen: CK_ULONG, - _pTemplate: CK_ATTRIBUTE_PTR, - _ulAttributeCount: CK_ULONG, - _phKey: CK_OBJECT_HANDLE_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_DeriveKey( - _hSession: CK_SESSION_HANDLE, - _pMechanism: CK_MECHANISM_PTR, - _hBaseKey: CK_OBJECT_HANDLE, - _pTemplate: CK_ATTRIBUTE_PTR, - _ulAttributeCount: CK_ULONG, - _phKey: CK_OBJECT_HANDLE_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_SeedRandom( - _hSession: CK_SESSION_HANDLE, - _pSeed: CK_BYTE_PTR, - _ulSeedLen: CK_ULONG, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_GenerateRandom( - _hSession: CK_SESSION_HANDLE, - _RandomData: CK_BYTE_PTR, - _ulRandomLen: CK_ULONG, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_GetFunctionStatus(_hSession: CK_SESSION_HANDLE) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_CancelFunction(_hSession: CK_SESSION_HANDLE) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -extern "C" fn C_WaitForSlotEvent( - _flags: CK_FLAGS, - _pSlot: CK_SLOT_ID_PTR, - _pRserved: CK_VOID_PTR, -) -> CK_RV { - CKR_FUNCTION_NOT_SUPPORTED -} - -/// To be a valid PKCS #11 module, this list of functions must be supported. At least cryptoki 2.2 -/// must be supported for this module to work in NSS. -static mut FUNCTION_LIST: CK_FUNCTION_LIST = CK_FUNCTION_LIST { - version: CK_VERSION { major: 2, minor: 2 }, - C_Initialize: Some(C_Initialize), - C_Finalize: Some(C_Finalize), - C_GetInfo: Some(C_GetInfo), - C_GetFunctionList: None, - C_GetSlotList: Some(C_GetSlotList), - C_GetSlotInfo: Some(C_GetSlotInfo), - C_GetTokenInfo: Some(C_GetTokenInfo), - C_GetMechanismList: Some(C_GetMechanismList), - C_GetMechanismInfo: Some(C_GetMechanismInfo), - C_InitToken: Some(C_InitToken), - C_InitPIN: Some(C_InitPIN), - C_SetPIN: Some(C_SetPIN), - C_OpenSession: Some(C_OpenSession), - C_CloseSession: Some(C_CloseSession), - C_CloseAllSessions: Some(C_CloseAllSessions), - C_GetSessionInfo: Some(C_GetSessionInfo), - C_GetOperationState: Some(C_GetOperationState), - C_SetOperationState: Some(C_SetOperationState), - C_Login: Some(C_Login), - C_Logout: Some(C_Logout), - C_CreateObject: Some(C_CreateObject), - C_CopyObject: Some(C_CopyObject), - C_DestroyObject: Some(C_DestroyObject), - C_GetObjectSize: Some(C_GetObjectSize), - C_GetAttributeValue: Some(C_GetAttributeValue), - C_SetAttributeValue: Some(C_SetAttributeValue), - C_FindObjectsInit: Some(C_FindObjectsInit), - C_FindObjects: Some(C_FindObjects), - C_FindObjectsFinal: Some(C_FindObjectsFinal), - C_EncryptInit: Some(C_EncryptInit), - C_Encrypt: Some(C_Encrypt), - C_EncryptUpdate: Some(C_EncryptUpdate), - C_EncryptFinal: Some(C_EncryptFinal), - C_DecryptInit: Some(C_DecryptInit), - C_Decrypt: Some(C_Decrypt), - C_DecryptUpdate: Some(C_DecryptUpdate), - C_DecryptFinal: Some(C_DecryptFinal), - C_DigestInit: Some(C_DigestInit), - C_Digest: Some(C_Digest), - C_DigestUpdate: Some(C_DigestUpdate), - C_DigestKey: Some(C_DigestKey), - C_DigestFinal: Some(C_DigestFinal), - C_SignInit: Some(C_SignInit), - C_Sign: Some(C_Sign), - C_SignUpdate: Some(C_SignUpdate), - C_SignFinal: Some(C_SignFinal), - C_SignRecoverInit: Some(C_SignRecoverInit), - C_SignRecover: Some(C_SignRecover), - C_VerifyInit: Some(C_VerifyInit), - C_Verify: Some(C_Verify), - C_VerifyUpdate: Some(C_VerifyUpdate), - C_VerifyFinal: Some(C_VerifyFinal), - C_VerifyRecoverInit: Some(C_VerifyRecoverInit), - C_VerifyRecover: Some(C_VerifyRecover), - C_DigestEncryptUpdate: Some(C_DigestEncryptUpdate), - C_DecryptDigestUpdate: Some(C_DecryptDigestUpdate), - C_SignEncryptUpdate: Some(C_SignEncryptUpdate), - C_DecryptVerifyUpdate: Some(C_DecryptVerifyUpdate), - C_GenerateKey: Some(C_GenerateKey), - C_GenerateKeyPair: Some(C_GenerateKeyPair), - C_WrapKey: Some(C_WrapKey), - C_UnwrapKey: Some(C_UnwrapKey), - C_DeriveKey: Some(C_DeriveKey), - C_SeedRandom: Some(C_SeedRandom), - C_GenerateRandom: Some(C_GenerateRandom), - C_GetFunctionStatus: Some(C_GetFunctionStatus), - C_CancelFunction: Some(C_CancelFunction), - C_WaitForSlotEvent: Some(C_WaitForSlotEvent), -}; - -/// This is the only function this module exposes. The C stub calls it when NSS -/// calls its exposed C_GetFunctionList function to obtain the list of functions -/// comprising this module. -#[no_mangle] -pub extern "C" fn IPCCC_GetFunctionList(ppFunctionList: CK_FUNCTION_LIST_PTR_PTR) -> CK_RV { - if ppFunctionList.is_null() { - return CKR_ARGUMENTS_BAD; - } - unsafe { - *ppFunctionList = &mut FUNCTION_LIST; - } - CKR_OK -} - -#[cfg_attr(target_os = "macos", link(name = "Security", kind = "framework"))] -extern "C" {} diff --git a/security/manager/ssl/moz.build b/security/manager/ssl/moz.build index 3a30b6dc52c4..6e94efac6bd6 100644 --- a/security/manager/ssl/moz.build +++ b/security/manager/ssl/moz.build @@ -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 += [ diff --git a/security/manager/ssl/nsNSSCallbacks.cpp b/security/manager/ssl/nsNSSCallbacks.cpp index 7bb3ac3efafb..1695b37be95f 100644 --- a/security/manager/ssl/nsNSSCallbacks.cpp +++ b/security/manager/ssl/nsNSSCallbacks.cpp @@ -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" diff --git a/security/manager/ssl/nsNSSComponent.cpp b/security/manager/ssl/nsNSSComponent.cpp index 0efd03fb0ade..af712b08099a 100644 --- a/security/manager/ssl/nsNSSComponent.cpp +++ b/security/manager/ssl/nsNSSComponent.cpp @@ -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& 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 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 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 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 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; diff --git a/security/manager/ssl/nsNSSIOLayer.cpp b/security/manager/ssl/nsNSSIOLayer.cpp index ab80a8e45c3e..81e06b269826 100644 --- a/security/manager/ssl/nsNSSIOLayer.cpp +++ b/security/manager/ssl/nsNSSIOLayer.cpp @@ -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> mCollectedCANames; nsTArray> mEnterpriseCertificates; UniqueCERTCertificate mSelectedCertificate; + UniqueSECKEYPrivateKey mSelectedKey; }; class RemoteClientAuthDataRunnable : public ClientAuthDataRunnable { @@ -1945,42 +1946,30 @@ SECStatus nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket, nsTArray> 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>&& collectedCANames, UniqueCERTCertificate& outCert, + UniqueSECKEYPrivateKey& outKey, UniqueCERTCertList& outBuiltChain) { // XXX: This should be done asynchronously; see bug 696976 RefPtr 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(cert.data().Elements()), - static_cast(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 GetIPCClientCertsActor() { - PBackgroundChild* backgroundActor = - BackgroundChild::GetOrCreateForSocketParentBridgeForCurrentThread(); - if (!backgroundActor) { - return nullptr; - } - RefPtr actor = - SingleManagedOrNull(backgroundActor->ManagedPIPCClientCertsChild()); - if (!actor) { - actor = backgroundActor->SendPIPCClientCertsConstructor( - new IPCClientCertsChild()); - if (!actor) { - return nullptr; - } - } - return actor.forget().downcast(); -} - -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 ipcClientCertsActor(GetIPCClientCertsActor()); - if (!ipcClientCertsActor) { - return; - } - nsTArray 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 ipcClientCertsActor(GetIPCClientCertsActor()); - if (!ipcClientCertsActor) { - return; - } - ByteArray certBytes(nsTArray(cert, cert_len)); - ByteArray dataBytes(nsTArray(data, data_len)); - ByteArray paramsBytes(nsTArray(params, params_len)); - ByteArray signature; - if (!ipcClientCertsActor->SendSign(certBytes, dataBytes, paramsBytes, - &signature)) { - return; - } - cb(signature.data().Length(), signature.data().Elements(), ctx); -} -} // extern "C" diff --git a/security/manager/ssl/nsNSSIOLayer.h b/security/manager/ssl/nsNSSIOLayer.h index af5ca0a3c3e1..ed36348cb52a 100644 --- a/security/manager/ssl/nsNSSIOLayer.h +++ b/security/manager/ssl/nsNSSIOLayer.h @@ -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>&& collectedCANames, mozilla::UniqueCERTCertificate& outCert, + mozilla::UniqueSECKEYPrivateKey& outKey, mozilla::UniqueCERTCertList& outBuiltChain); #endif // nsNSSIOLayer_h diff --git a/security/manager/ssl/osclientcerts/src/lib.rs b/security/manager/ssl/osclientcerts/src/lib.rs index a1986f66bb96..add9880c05e2 100644 --- a/security/manager/ssl/osclientcerts/src/lib.rs +++ b/security/manager/ssl/osclientcerts/src/lib.rs @@ -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); }; } diff --git a/security/manager/ssl/rsclientcerts/src/manager.rs b/security/manager/ssl/rsclientcerts/src/manager.rs index b8b47dcc9b7b..3ad026fec4f0 100644 --- a/security/manager/ssl/rsclientcerts/src/manager.rs +++ b/security/manager/ssl/rsclientcerts/src/manager.rs @@ -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 Object { fn get_signature_length( &mut self, - data: Vec, + data: &[u8], params: &Option, ) -> Result { 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, + data: &[u8], params: &Option, ) -> Result, 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 Object { /// 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 { +struct Manager { /// A map of session to session type (modern or legacy). Sessions can be created (opened) and /// later closed. sessions: BTreeMap, @@ -546,7 +546,7 @@ impl Manager { pub fn start_search( &mut self, session: CK_SESSION_HANDLE, - attrs: Vec<(CK_ATTRIBUTE_TYPE, Vec)>, + attrs: &[(CK_ATTRIBUTE_TYPE, Vec)], ) -> Result<(), Error> { let slot_type = match self.sessions.get(&session) { Some(slot_type) => *slot_type, @@ -554,7 +554,7 @@ impl Manager { }; // 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 Manager { // 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 Manager { pub fn get_signature_length( &mut self, session: CK_SESSION_HANDLE, - data: Vec, + data: &[u8], ) -> Result { let (key_handle, params) = match self.signs.get(&session) { Some((key_handle, params)) => (key_handle, params), @@ -664,7 +664,7 @@ impl Manager { key.get_signature_length(data, params) } - pub fn sign(&mut self, session: CK_SESSION_HANDLE, data: Vec) -> Result, Error> { + pub fn sign(&mut self, session: CK_SESSION_HANDLE, data: &[u8]) -> Result, 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) {