diff -up firefox-128.2.0/dom/crypto/WebCryptoTask.cpp.webrtc firefox-128.2.0/dom/crypto/WebCryptoTask.cpp --- firefox-128.2.0/dom/crypto/WebCryptoTask.cpp.webrtc 2024-08-26 16:23:34.000000000 +0200 +++ firefox-128.2.0/dom/crypto/WebCryptoTask.cpp 2024-09-30 21:42:30.750124316 +0200 @@ -118,60 +118,6 @@ enum TelemetryAlgorithm { } \ } -class ClearException { - public: - explicit ClearException(JSContext* aCx) : mCx(aCx) {} - - ~ClearException() { JS_ClearPendingException(mCx); } - - private: - JSContext* mCx; -}; - -template -static nsresult GetAlgorithmName(JSContext* aCx, const OOS& aAlgorithm, - nsString& aName) { - ClearException ce(aCx); - - if (aAlgorithm.IsString()) { - // If string, then treat as algorithm name - aName.Assign(aAlgorithm.GetAsString()); - } else { - // Coerce to algorithm and extract name - JS::Rooted value(aCx, - JS::ObjectValue(*aAlgorithm.GetAsObject())); - Algorithm alg; - - if (!alg.Init(aCx, value)) { - return NS_ERROR_DOM_SYNTAX_ERR; - } - - aName = alg.mName; - } - - if (!NormalizeToken(aName, aName)) { - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; - } - - return NS_OK; -} - -template -static nsresult Coerce(JSContext* aCx, T& aTarget, const OOS& aAlgorithm) { - ClearException ce(aCx); - - if (!aAlgorithm.IsObject()) { - return NS_ERROR_DOM_SYNTAX_ERR; - } - - JS::Rooted value(aCx, JS::ObjectValue(*aAlgorithm.GetAsObject())); - if (!aTarget.Init(aCx, value)) { - return NS_ERROR_DOM_TYPE_MISMATCH_ERR; - } - - return NS_OK; -} - inline size_t MapHashAlgorithmNameToBlockSize(const nsString& aName) { if (aName.EqualsLiteral(WEBCRYPTO_ALG_SHA1) || aName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) { @@ -2198,6 +2144,30 @@ class GenerateSymmetricKeyTask : public virtual void Cleanup() override { mKey = nullptr; } }; +class GenerateAsymmetricKeyTask : public WebCryptoTask { + public: + GenerateAsymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, + const ObjectOrString& aAlgorithm, bool aExtractable, + const Sequence& aKeyUsages); + + protected: + UniquePLArenaPool mArena; + UniquePtr mKeyPair; + nsString mAlgName; + CK_MECHANISM_TYPE mMechanism; + PK11RSAGenParams mRsaParams; + SECKEYDHParams mDhParams; + nsString mNamedCurve; + + virtual nsresult DoCrypto() override; + virtual void Resolve() override; + virtual void Cleanup() override; + + private: + UniqueSECKEYPublicKey mPublicKey; + UniqueSECKEYPrivateKey mPrivateKey; +}; + GenerateAsymmetricKeyTask::GenerateAsymmetricKeyTask( nsIGlobalObject* aGlobal, JSContext* aCx, const ObjectOrString& aAlgorithm, bool aExtractable, const Sequence& aKeyUsages) diff -up firefox-128.2.0/dom/crypto/WebCryptoTask.h.webrtc firefox-128.2.0/dom/crypto/WebCryptoTask.h --- firefox-128.2.0/dom/crypto/WebCryptoTask.h.webrtc 2024-08-26 16:23:34.000000000 +0200 +++ firefox-128.2.0/dom/crypto/WebCryptoTask.h 2024-09-30 21:41:07.648369048 +0200 @@ -175,31 +175,60 @@ class WebCryptoTask : public CancelableR nsresult mRv; }; -// XXX This class is declared here (unlike others) to enable reuse by WebRTC. -class GenerateAsymmetricKeyTask : public WebCryptoTask { +class ClearException { public: - GenerateAsymmetricKeyTask(nsIGlobalObject* aGlobal, JSContext* aCx, - const ObjectOrString& aAlgorithm, bool aExtractable, - const Sequence& aKeyUsages); - - protected: - UniquePLArenaPool mArena; - UniquePtr mKeyPair; - nsString mAlgName; - CK_MECHANISM_TYPE mMechanism; - PK11RSAGenParams mRsaParams; - SECKEYDHParams mDhParams; - nsString mNamedCurve; - - virtual nsresult DoCrypto() override; - virtual void Resolve() override; - virtual void Cleanup() override; + explicit ClearException(JSContext* aCx) : mCx(aCx) {} + + ~ClearException() { JS_ClearPendingException(mCx); } private: - UniqueSECKEYPublicKey mPublicKey; - UniqueSECKEYPrivateKey mPrivateKey; + JSContext* mCx; }; +template +nsresult GetAlgorithmName(JSContext* aCx, const OOS& aAlgorithm, + nsString& aName) { + ClearException ce(aCx); + + if (aAlgorithm.IsString()) { + // If string, then treat as algorithm name + aName.Assign(aAlgorithm.GetAsString()); + } else { + // Coerce to algorithm and extract name + JS::Rooted value(aCx, + JS::ObjectValue(*aAlgorithm.GetAsObject())); + Algorithm alg; + + if (!alg.Init(aCx, value)) { + return NS_ERROR_DOM_SYNTAX_ERR; + } + + aName = alg.mName; + } + + if (!NormalizeToken(aName, aName)) { + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + } + + return NS_OK; +} + +template +nsresult Coerce(JSContext* aCx, T& aTarget, const OOS& aAlgorithm) { + ClearException ce(aCx); + + if (!aAlgorithm.IsObject()) { + return NS_ERROR_DOM_SYNTAX_ERR; + } + + JS::Rooted value(aCx, JS::ObjectValue(*aAlgorithm.GetAsObject())); + if (!aTarget.Init(aCx, value)) { + return NS_ERROR_DOM_TYPE_MISMATCH_ERR; + } + + return NS_OK; +} + } // namespace mozilla::dom #endif // mozilla_dom_WebCryptoTask_h diff -up firefox-128.2.0/dom/media/webrtc/components.conf.webrtc firefox-128.2.0/dom/media/webrtc/components.conf --- firefox-128.2.0/dom/media/webrtc/components.conf.webrtc 2024-09-30 21:41:07.649369081 +0200 +++ firefox-128.2.0/dom/media/webrtc/components.conf 2024-09-30 21:41:07.649369081 +0200 @@ -0,0 +1,14 @@ +# -*- 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/. + +Classes = [ + { + 'cid': '{e665acb0-5952-11ef-bb8c-18c04d07c34d}', + 'contract_ids': ['@mozilla.org/rtccert/service;1'], + 'headers': ['/dom/media/webrtc/RTCCertService.h'], + 'constructor': 'mozilla::dom::NewRTCCertService', + }, +] diff -up firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandler.cpp.webrtc firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandler.cpp --- firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandler.cpp.webrtc 2024-08-26 16:23:34.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandler.cpp 2024-09-30 21:41:07.649369081 +0200 @@ -104,13 +104,15 @@ class MediaTransportHandlerSTS : public // via IPC anymore const nsTArray& aStunAddrs) override; - void ActivateTransport( - const std::string& aTransportId, const std::string& aLocalUfrag, - const std::string& aLocalPwd, size_t aComponentCount, - const std::string& aUfrag, const std::string& aPassword, - const nsTArray& aKeyDer, const nsTArray& aCertDer, - SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, - bool aPrivacyRequested) override; + void ActivateTransport(const std::string& aTransportId, + const std::string& aLocalUfrag, + const std::string& aLocalPwd, size_t aComponentCount, + const std::string& aUfrag, + const std::string& aPassword, + const nsTArray& aCertFingerprint, + SSLKEAType aAuthType, bool aDtlsClient, + const DtlsDigestList& aDigests, + bool aPrivacyRequested) override; void RemoveTransportsExcept( const std::set& aTransportIds) override; @@ -799,14 +801,13 @@ void MediaTransportHandlerSTS::ActivateT const std::string& aTransportId, const std::string& aLocalUfrag, const std::string& aLocalPwd, size_t aComponentCount, const std::string& aUfrag, const std::string& aPassword, - const nsTArray& aKeyDer, const nsTArray& aCertDer, - SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, - bool aPrivacyRequested) { + const nsTArray& aCertFingerprint, SSLKEAType aAuthType, + bool aDtlsClient, const DtlsDigestList& aDigests, bool aPrivacyRequested) { MOZ_RELEASE_ASSERT(mInitPromise); mInitPromise->Then( mStsThread, __func__, - [=, keyDer = aKeyDer.Clone(), certDer = aCertDer.Clone(), + [=, aCertFingerprint = aCertFingerprint.Clone(), self = RefPtr(this)]() { if (!mIceCtx) { return; // Probably due to XPCOM shutdown @@ -814,7 +815,7 @@ void MediaTransportHandlerSTS::ActivateT MOZ_ASSERT(aComponentCount); RefPtr dtlsIdentity( - DtlsIdentity::Deserialize(keyDer, certDer, aAuthType)); + DtlsIdentity::Deserialize(aCertFingerprint, aAuthType)); if (!dtlsIdentity) { MOZ_ASSERT(false); return; diff -up firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandler.h.webrtc firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandler.h --- firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandler.h.webrtc 2024-08-26 16:23:34.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandler.h 2024-09-30 21:41:07.650369114 +0200 @@ -98,8 +98,8 @@ class MediaTransportHandler { const std::string& aTransportId, const std::string& aLocalUfrag, const std::string& aLocalPwd, size_t aComponentCount, const std::string& aUfrag, const std::string& aPassword, - const nsTArray& aKeyDer, const nsTArray& aCertDer, - SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, + const nsTArray& aCertFingerprint, SSLKEAType aAuthType, + bool aDtlsClient, const DtlsDigestList& aDigests, bool aPrivacyRequested) = 0; virtual void RemoveTransportsExcept( diff -up firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp.webrtc firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp --- firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp.webrtc 2024-08-26 16:23:34.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp 2024-09-30 21:41:07.650369114 +0200 @@ -269,17 +269,16 @@ void MediaTransportHandlerIPC::ActivateT const std::string& aTransportId, const std::string& aLocalUfrag, const std::string& aLocalPwd, size_t aComponentCount, const std::string& aUfrag, const std::string& aPassword, - const nsTArray& aKeyDer, const nsTArray& aCertDer, - SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, - bool aPrivacyRequested) { + const nsTArray& aCertFingerprint, SSLKEAType aAuthType, + bool aDtlsClient, const DtlsDigestList& aDigests, bool aPrivacyRequested) { mInitPromise->Then( mCallbackThread, __func__, - [=, keyDer = aKeyDer.Clone(), certDer = aCertDer.Clone(), + [=, certFingerprint = aCertFingerprint.Clone(), self = RefPtr(this)](bool /*dummy*/) { if (mChild) { mChild->SendActivateTransport(aTransportId, aLocalUfrag, aLocalPwd, aComponentCount, aUfrag, aPassword, - keyDer, certDer, aAuthType, aDtlsClient, + certFingerprint, aAuthType, aDtlsClient, aDigests, aPrivacyRequested); } }, diff -up firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.h.webrtc firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.h --- firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.h.webrtc 2024-08-26 16:23:34.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.h 2024-09-30 21:41:07.650369114 +0200 @@ -49,13 +49,15 @@ class MediaTransportHandlerIPC final : p // this up internally const nsTArray& aStunAddrs) override; - void ActivateTransport( - const std::string& aTransportId, const std::string& aLocalUfrag, - const std::string& aLocalPwd, size_t aComponentCount, - const std::string& aUfrag, const std::string& aPassword, - const nsTArray& aKeyDer, const nsTArray& aCertDer, - SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, - bool aPrivacyRequested) override; + void ActivateTransport(const std::string& aTransportId, + const std::string& aLocalUfrag, + const std::string& aLocalPwd, size_t aComponentCount, + const std::string& aUfrag, + const std::string& aPassword, + const nsTArray& aCertFingerprint, + SSLKEAType aAuthType, bool aDtlsClient, + const DtlsDigestList& aDigests, + bool aPrivacyRequested) override; void RemoveTransportsExcept( const std::set& aTransportIds) override; diff -up firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportParent.cpp.webrtc firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportParent.cpp --- firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportParent.cpp.webrtc 2024-08-26 16:23:34.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/jsapi/MediaTransportParent.cpp 2024-09-30 21:41:07.650369114 +0200 @@ -174,12 +174,12 @@ mozilla::ipc::IPCResult MediaTransportPa mozilla::ipc::IPCResult MediaTransportParent::RecvActivateTransport( const string& transportId, const string& localUfrag, const string& localPwd, const int& componentCount, const string& remoteUfrag, - const string& remotePwd, nsTArray&& keyDer, - nsTArray&& certDer, const int& authType, const bool& dtlsClient, - const DtlsDigestList& digests, const bool& privacyRequested) { + const string& remotePwd, nsTArray&& certFingerprint, + const int& authType, const bool& dtlsClient, const DtlsDigestList& digests, + const bool& privacyRequested) { mImpl->mHandler->ActivateTransport( transportId, localUfrag, localPwd, componentCount, remoteUfrag, remotePwd, - keyDer, certDer, static_cast(authType), dtlsClient, digests, + certFingerprint, static_cast(authType), dtlsClient, digests, privacyRequested); return ipc::IPCResult::Ok(); } diff -up firefox-128.2.0/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp.webrtc firefox-128.2.0/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp --- firefox-128.2.0/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp.webrtc 2024-08-26 16:23:35.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp 2024-09-30 21:41:07.650369114 +0200 @@ -4353,9 +4353,8 @@ void PeerConnectionImpl::UpdateTransport candidates.end()); } - nsTArray keyDer; - nsTArray certDer; - nsresult rv = Identity()->Serialize(&keyDer, &certDer); + nsTArray certFingerprint; + nsresult rv = Identity()->Serialize(certFingerprint); if (NS_FAILED(rv)) { CSFLogError(LOGTAG, "%s: Failed to serialize DTLS identity: %d", __FUNCTION__, (int)rv); @@ -4371,7 +4370,7 @@ void PeerConnectionImpl::UpdateTransport mTransportHandler->ActivateTransport( transport.mTransportId, transport.mLocalUfrag, transport.mLocalPwd, - components, ufrag, pwd, keyDer, certDer, Identity()->auth_type(), + components, ufrag, pwd, certFingerprint, Identity()->auth_type(), transport.mDtls->GetRole() == JsepDtlsTransport::kJsepDtlsClient, digests, PrivacyRequested()); diff -up firefox-128.2.0/dom/media/webrtc/MediaTransportParent.h.webrtc firefox-128.2.0/dom/media/webrtc/MediaTransportParent.h --- firefox-128.2.0/dom/media/webrtc/MediaTransportParent.h.webrtc 2024-08-26 16:23:34.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/MediaTransportParent.h 2024-09-30 21:41:07.648369048 +0200 @@ -40,9 +40,9 @@ class MediaTransportParent : public dom: const string& transportId, const string& localUfrag, const string& localPwd, const int& componentCount, const string& remoteUfrag, const string& remotePwd, - nsTArray&& keyDer, nsTArray&& certDer, - const int& authType, const bool& dtlsClient, - const DtlsDigestList& digests, const bool& privacyRequested); + nsTArray&& certFingerprint, const int& authType, + const bool& dtlsClient, const DtlsDigestList& digests, + const bool& privacyRequested); mozilla::ipc::IPCResult RecvRemoveTransportsExcept( const StringVector& transportIds); mozilla::ipc::IPCResult RecvStartIceChecks(const bool& isControlling, diff -up firefox-128.2.0/dom/media/webrtc/moz.build.webrtc firefox-128.2.0/dom/media/webrtc/moz.build --- firefox-128.2.0/dom/media/webrtc/moz.build.webrtc 2024-08-26 16:23:34.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/moz.build 2024-09-30 21:41:07.650369114 +0200 @@ -41,6 +41,18 @@ SOURCES += [ "CubebDeviceEnumerator.cpp", ] +XPCOM_MANIFESTS += [ + "components.conf", +] + +IPDL_SOURCES += ["PRTCCertServiceTransaction.ipdl"] + +XPIDL_SOURCES += [ + "nsIRTCCertService.idl", +] + +XPIDL_MODULE = "rtc_certservice" + if CONFIG["MOZ_WEBRTC"]: EXPORTS += [ "MediaEngineRemoteVideoSource.h", @@ -51,7 +63,11 @@ if CONFIG["MOZ_WEBRTC"]: UNIFIED_SOURCES += [ "MediaEngineRemoteVideoSource.cpp", "MediaEngineWebRTCAudio.cpp", + "RTCCertCache.cpp", "RTCCertificate.cpp", + "RTCCertService.cpp", + "RTCCertServiceData.cpp", + "RTCCertServiceParent.cpp", "RTCIdentityProviderRegistrar.cpp", ] # MediaEngineWebRTC.cpp needs to be built separately. @@ -113,7 +129,11 @@ EXPORTS.mozilla += [ "PeerIdentity.h", ] EXPORTS.mozilla.dom += [ + "RTCCertCache.h", "RTCCertificate.h", + "RTCCertService.h", + "RTCCertServiceData.h", + "RTCCertServiceParent.h", ] include("/ipc/chromium/chromium-config.mozbuild") diff -up firefox-128.2.0/dom/media/webrtc/nsIRTCCertService.idl.webrtc firefox-128.2.0/dom/media/webrtc/nsIRTCCertService.idl --- firefox-128.2.0/dom/media/webrtc/nsIRTCCertService.idl.webrtc 2024-09-30 21:41:07.651369147 +0200 +++ firefox-128.2.0/dom/media/webrtc/nsIRTCCertService.idl 2024-09-30 21:41:07.650369114 +0200 @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-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/. */ + +#include "nsISupports.idl" + +%{C++ +#include "mozilla/dom/RTCCertServiceData.h" +%} + +native CertFingerprint(mozilla::dom::CertFingerprint); +native RTCCertFingerprintPromise(RefPtr); + +native CertData(mozilla::dom::CertData); +native RTCCertificatePromise(RefPtr); + +[ptr] native CERTCertificate(CERTCertificate); + +[uuid(e665acb0-5952-11ef-bb8c-18c04d07c34d)] +interface nsIRTCCertService : nsISupports +{ + // Init the class + [notxpcom, nostdcall] void Initialize(); + + // Generate cert + [notxpcom, nostdcall] RTCCertFingerprintPromise GenerateCertificate(in Array aParam, in PRTime aExpires, in unsigned long aMechanism, in uint32_t aSignatureAlg); + + // Remove cert + [notxpcom, nostdcall] void RemoveCertificate([const] in CertFingerprint aCertFingerprint); + + // Get cert + [notxpcom, nostdcall] RTCCertificatePromise getCertificate([const] in CertFingerprint aCertFingerprint); +}; diff -up firefox-128.2.0/dom/media/webrtc/PMediaTransport.ipdl.webrtc firefox-128.2.0/dom/media/webrtc/PMediaTransport.ipdl --- firefox-128.2.0/dom/media/webrtc/PMediaTransport.ipdl.webrtc 2024-08-26 16:23:35.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/PMediaTransport.ipdl 2024-09-30 21:41:07.648369048 +0200 @@ -62,8 +62,7 @@ parent: int componentCount, string remoteUfrag, string remotePwd, - uint8_t[] keyDer, - uint8_t[] certDer, + uint8_t[] certFingerprint, int authType, bool dtlsClient, DtlsDigestList digests, diff -up firefox-128.2.0/dom/media/webrtc/PRTCCertServiceTransaction.ipdl.webrtc firefox-128.2.0/dom/media/webrtc/PRTCCertServiceTransaction.ipdl --- firefox-128.2.0/dom/media/webrtc/PRTCCertServiceTransaction.ipdl.webrtc 2024-09-30 21:41:07.648369048 +0200 +++ firefox-128.2.0/dom/media/webrtc/PRTCCertServiceTransaction.ipdl 2024-09-30 21:41:07.648369048 +0200 @@ -0,0 +1,33 @@ +/* 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/. */ + +/* + * IPC Transaction protocol for the Cert Service DOM API. + * This IPC protocol allows to generate private / public keys and certificate + * in socket process and return public key and certificate back to + * content process. + */ + +include protocol PBackground; + +using PRTime from "prtime.h"; +using mozilla::dom::CertFingerprint from "mozilla/dom/RTCCertServiceData.h"; +using mozilla::dom::CertDataIPC from "mozilla/dom/RTCCertServiceData.h"; + +namespace mozilla { +namespace dom { + +[ParentProc=Socket, ChildProc=Content, ChildImpl=virtual, ParentImpl=virtual] +async protocol PRTCCertServiceTransaction { + parent: + async GenerateCertificate(uint8_t[] aParam, PRTime aExpires, uint32_t aMechanism, uint32_t aSignatureAlg) returns (CertFingerprint fingerprint); + async RemoveCertificate(CertFingerprint aCertFingerprint); + async GetCertificate(CertFingerprint aCertFingerprint) returns (CertDataIPC certificate); + + child: + async __delete__(); +}; + +} +} diff -up firefox-128.2.0/dom/media/webrtc/RTCCertCache.cpp.webrtc firefox-128.2.0/dom/media/webrtc/RTCCertCache.cpp --- firefox-128.2.0/dom/media/webrtc/RTCCertCache.cpp.webrtc 2024-09-30 21:41:07.648369048 +0200 +++ firefox-128.2.0/dom/media/webrtc/RTCCertCache.cpp 2024-09-30 21:41:07.648369048 +0200 @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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 "RTCCertCache.h" + +namespace mozilla::dom { + +nsTArray> RTCCertCache::sCertCache; +mozilla::StaticMutex RTCCertCache::sRTCCertCacheLock MOZ_UNANNOTATED; + +void RTCCertCache::CacheCert(UniquePtr aCert) { + StaticMutexAutoLock CacheLock(sRTCCertCacheLock); + for (size_t i = 0; i < sCertCache.Length(); i++) { + if (!sCertCache[i]) { + sCertCache[i] = std::move(aCert); + return; + } + } + sCertCache.AppendElement(std::move(aCert)); +} + +GeneratedCertificate* RTCCertCache::LookupCert( + const CertFingerprint aCertFingerprint) { + StaticMutexAutoLock CacheLock(sRTCCertCacheLock); + for (size_t i = 0; i < sCertCache.Length(); i++) { + if (sCertCache[i] && + sCertCache[i]->mCertFingerprint.Match(&aCertFingerprint)) { + return sCertCache[i].get(); + } + } + return nullptr; +} + +void RTCCertCache::RemoveCert(const CertFingerprint aCertFingerprint) { + StaticMutexAutoLock CacheLock(sRTCCertCacheLock); + for (size_t i = 0; i < sCertCache.Length(); i++) { + if (sCertCache[i] && + sCertCache[i]->mCertFingerprint.Match(&aCertFingerprint)) { + sCertCache[i] = nullptr; + break; + } + } +} + +} // namespace mozilla::dom diff -up firefox-128.2.0/dom/media/webrtc/RTCCertCache.h.webrtc firefox-128.2.0/dom/media/webrtc/RTCCertCache.h --- firefox-128.2.0/dom/media/webrtc/RTCCertCache.h.webrtc 2024-09-30 21:41:07.648369048 +0200 +++ firefox-128.2.0/dom/media/webrtc/RTCCertCache.h 2024-09-30 21:41:07.648369048 +0200 @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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_dom_CertCache_h +#define mozilla_dom_CertCache_h + +#include "mozilla/dom/RTCCertServiceData.h" +#include "mozilla/StaticMutex.h" + +namespace mozilla::dom { + +struct GeneratedCertificate { + UniqueSECKEYPublicKey mPublicKey; + UniqueSECKEYPrivateKey mPrivateKey; + UniqueCERTCertificate mCertificate; + CertFingerprint mCertFingerprint; + PRTime mExpires = 0; +}; + +class RTCCertCache { + public: + static void CacheCert(UniquePtr aCert); + static GeneratedCertificate* LookupCert( + const CertFingerprint aCertFingerprint); + static void RemoveCert(const CertFingerprint aCertFingerprint); + + private: + static nsTArray> sCertCache; + static mozilla::StaticMutex sRTCCertCacheLock MOZ_UNANNOTATED; +}; +} // namespace mozilla::dom + +#endif // mozilla_dom_CertCache_h diff -up firefox-128.2.0/dom/media/webrtc/RTCCertificate.cpp.webrtc firefox-128.2.0/dom/media/webrtc/RTCCertificate.cpp --- firefox-128.2.0/dom/media/webrtc/RTCCertificate.cpp.webrtc 2024-08-26 16:23:35.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/RTCCertificate.cpp 2024-09-30 21:41:07.649369081 +0200 @@ -25,13 +25,12 @@ #include "mozilla/UniquePtr.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/CryptoBuffer.h" -#include "mozilla/dom/CryptoKey.h" #include "mozilla/dom/KeyAlgorithmBinding.h" #include "mozilla/dom/KeyAlgorithmProxy.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/RTCCertificateBinding.h" +#include "mozilla/dom/RootedDictionary.h" #include "mozilla/dom/StructuredCloneHolder.h" -#include "mozilla/dom/SubtleCryptoBinding.h" #include "mozilla/dom/UnionTypes.h" #include "mozilla/dom/WebCryptoCommon.h" #include "mozilla/dom/WebCryptoTask.h" @@ -42,6 +41,7 @@ #include "nsStringFlags.h" #include "nsStringFwd.h" #include "nsTLiteralString.h" +#include "nsServiceManagerUtils.h" #include "pk11pub.h" #include "plarena.h" #include "secasn1.h" @@ -71,271 +71,203 @@ NS_INTERFACE_MAP_END PRTime(PR_USEC_PER_SEC) * PRTime(60) /*sec*/ \ * PRTime(60) /*min*/ * PRTime(24) /*hours*/ #define EXPIRATION_DEFAULT ONE_DAY* PRTime(30) -#define EXPIRATION_SLACK ONE_DAY #define EXPIRATION_MAX ONE_DAY* PRTime(365) /*year*/ -const size_t RTCCertificateCommonNameLength = 16; const size_t RTCCertificateMinRsaSize = 1024; -class GenerateRTCCertificateTask : public GenerateAsymmetricKeyTask { - public: - GenerateRTCCertificateTask(nsIGlobalObject* aGlobal, JSContext* aCx, - const ObjectOrString& aAlgorithm, - const Sequence& aKeyUsages, - PRTime aExpires) - : GenerateAsymmetricKeyTask(aGlobal, aCx, aAlgorithm, true, aKeyUsages), - mExpires(aExpires), - mAuthType(ssl_kea_null), - mCertificate(nullptr), - mSignatureAlg(SEC_OID_UNKNOWN) { - if (NS_FAILED(mEarlyRv)) { - // webrtc-pc says to throw NotSupportedError if we have passed "an - // algorithm that the user agent cannot or will not use to generate a - // certificate". This catches these cases. - mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR; - } +static PRTime ReadExpires(JSContext* aCx, const ObjectOrString& aOptions, + ErrorResult& aRv) { + // This conversion might fail, but we don't really care; use the default. + // If this isn't an object, or it doesn't coerce into the right type, + // then we won't get the |expires| value. Either will be caught later. + RTCCertificateExpiration expiration; + if (!aOptions.IsObject()) { + return EXPIRATION_DEFAULT; } - - private: - PRTime mExpires; - SSLKEAType mAuthType; - UniqueCERTCertificate mCertificate; - SECOidTag mSignatureAlg; - - static CERTName* GenerateRandomName(PK11SlotInfo* aSlot) { - uint8_t randomName[RTCCertificateCommonNameLength]; - SECStatus rv = - PK11_GenerateRandomOnSlot(aSlot, randomName, sizeof(randomName)); - if (rv != SECSuccess) { - return nullptr; - } - - char buf[sizeof(randomName) * 2 + 4]; - strncpy(buf, "CN=", 4); - for (size_t i = 0; i < sizeof(randomName); ++i) { - snprintf(&buf[i * 2 + 3], 3, "%.2x", randomName[i]); - } - buf[sizeof(buf) - 1] = '\0'; - - return CERT_AsciiToName(buf); + JS::Rooted value(aCx, JS::ObjectValue(*aOptions.GetAsObject())); + if (!expiration.Init(aCx, value)) { + aRv.NoteJSContextException(aCx); + return 0; } - nsresult GenerateCertificate() { - UniquePK11SlotInfo slot(PK11_GetInternalSlot()); - MOZ_ASSERT(slot.get()); - - UniqueCERTName subjectName(GenerateRandomName(slot.get())); - if (!subjectName) { - return NS_ERROR_DOM_UNKNOWN_ERR; - } + if (!expiration.mExpires.WasPassed()) { + return EXPIRATION_DEFAULT; + } + static const uint64_t max = + static_cast(EXPIRATION_MAX / PR_USEC_PER_MSEC); + if (expiration.mExpires.Value() > max) { + return EXPIRATION_MAX; + } + return static_cast(expiration.mExpires.Value() * PR_USEC_PER_MSEC); +} - UniqueSECKEYPublicKey publicKey(mKeyPair->mPublicKey->GetPublicKey()); - UniqueCERTSubjectPublicKeyInfo spki( - SECKEY_CreateSubjectPublicKeyInfo(publicKey.get())); - if (!spki) { - return NS_ERROR_DOM_UNKNOWN_ERR; - } +RTCCertificateMetadata::RTCCertificateMetadata() + : mExpires(0), + mSignatureAlg(SEC_OID_UNKNOWN), + mMechanism(CKM_INVALID_MECHANISM), + mRsaParams() {} + +nsresult RTCCertificateMetadata::Init(JSContext* aCx, + const ObjectOrString& aAlgorithm, + SSLKEAType* aAuthType, ErrorResult& aRv) { + mExpires = ReadExpires(aCx, aAlgorithm, aRv); + if (aRv.Failed()) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } - UniqueCERTCertificateRequest certreq( - CERT_CreateCertificateRequest(subjectName.get(), spki.get(), nullptr)); - if (!certreq) { - return NS_ERROR_DOM_UNKNOWN_ERR; - } + mArena = UniquePLArenaPool(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + if (!mArena) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } - PRTime now = PR_Now(); - PRTime notBefore = now - EXPIRATION_SLACK; - mExpires += now; + // Extract algorithm name + nsresult rv = GetAlgorithmName(aCx, aAlgorithm, mAlgName); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_NOT_SUPPORTED_ERR); - UniqueCERTValidity validity(CERT_CreateValidity(notBefore, mExpires)); - if (!validity) { - return NS_ERROR_DOM_UNKNOWN_ERR; - } + // Construct an appropriate KeyAlorithm + if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { + RootedDictionary params(aCx); + rv = Coerce(aCx, params, aAlgorithm); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR); - unsigned long serial; - // Note: This serial in principle could collide, but it's unlikely, and we - // don't expect anyone to be validating certificates anyway. - SECStatus rv = PK11_GenerateRandomOnSlot( - slot.get(), reinterpret_cast(&serial), sizeof(serial)); - if (rv != SECSuccess) { + // Pull relevant info + uint32_t modulusLength = params.mModulusLength; + CryptoBuffer publicExponent; + if (!publicExponent.Assign(params.mPublicExponent)) { return NS_ERROR_DOM_UNKNOWN_ERR; } - // NB: CERTCertificates created with CERT_CreateCertificate are not safe to - // use with other NSS functions like CERT_DupCertificate. The strategy - // here is to create a tbsCertificate ("to-be-signed certificate"), encode - // it, and sign it, resulting in a signed DER certificate that can be - // decoded into a CERTCertificate. - UniqueCERTCertificate tbsCertificate(CERT_CreateCertificate( - serial, subjectName.get(), validity.get(), certreq.get())); - if (!tbsCertificate) { - return NS_ERROR_DOM_UNKNOWN_ERR; + nsString hashName; + rv = GetAlgorithmName(aCx, params.mHash, hashName); + NS_ENSURE_SUCCESS(rv, rv); + if (!hashName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) { + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } - MOZ_ASSERT(mSignatureAlg != SEC_OID_UNKNOWN); - PLArenaPool* arena = tbsCertificate->arena; + mMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; - rv = SECOID_SetAlgorithmID(arena, &tbsCertificate->signature, mSignatureAlg, - nullptr); - if (rv != SECSuccess) { - return NS_ERROR_DOM_UNKNOWN_ERR; + // Set up params struct + mRsaParams.keySizeInBits = modulusLength; + bool converted = publicExponent.GetBigIntValue(mRsaParams.pe); + if (!converted) { + return NS_ERROR_DOM_INVALID_ACCESS_ERR; } - // Set version to X509v3. - *(tbsCertificate->version.data) = SEC_CERTIFICATE_VERSION_3; - tbsCertificate->version.len = 1; - - SECItem innerDER = {siBuffer, nullptr, 0}; - if (!SEC_ASN1EncodeItem(arena, &innerDER, tbsCertificate.get(), - SEC_ASN1_GET(CERT_CertificateTemplate))) { - return NS_ERROR_DOM_UNKNOWN_ERR; + auto sz = static_cast(mRsaParams.keySizeInBits); + if (sz < RTCCertificateMinRsaSize) { + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } - SECItem* certDer = PORT_ArenaZNew(arena, SECItem); - if (!certDer) { - return NS_ERROR_DOM_UNKNOWN_ERR; - } + SerializeRSAParam(&mParam, &mRsaParams); - UniqueSECKEYPrivateKey privateKey(mKeyPair->mPrivateKey->GetPrivateKey()); - rv = SEC_DerSignData(arena, certDer, innerDER.data, innerDER.len, - privateKey.get(), mSignatureAlg); - if (rv != SECSuccess) { - return NS_ERROR_DOM_UNKNOWN_ERR; - } + mSignatureAlg = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; + *aAuthType = ssl_kea_rsa; + } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { + RootedDictionary params(aCx); + rv = Coerce(aCx, params, aAlgorithm); + NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR); - mCertificate.reset(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certDer, - nullptr, false, true)); - if (!mCertificate) { - return NS_ERROR_DOM_UNKNOWN_ERR; + if (!NormalizeToken(params.mNamedCurve, mNamedCurve)) { + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } - return NS_OK; - } - - nsresult BeforeCrypto() override { - if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) { - // Double check that size is OK. - auto sz = static_cast(mRsaParams.keySizeInBits); - if (sz < RTCCertificateMinRsaSize) { - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; - } - - KeyAlgorithmProxy& alg = mKeyPair->mPublicKey->Algorithm(); - if (alg.mType != KeyAlgorithmProxy::RSA || - !alg.mRsa.mHash.mName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) { - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; - } - - mSignatureAlg = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; - mAuthType = ssl_kea_rsa; - - } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) { - // We only support good curves in WebCrypto. - // If that ever changes, check that a good one was chosen. - - mSignatureAlg = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; - mAuthType = ssl_kea_ecdh; - } else { + mMechanism = CKM_EC_KEY_PAIR_GEN; + if (!SerializeECParams(&mParam, + CreateECParamsForCurve(mNamedCurve, mArena.get()))) { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } - return NS_OK; - } - nsresult DoCrypto() override { - nsresult rv = GenerateAsymmetricKeyTask::DoCrypto(); - NS_ENSURE_SUCCESS(rv, rv); - - rv = GenerateCertificate(); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; + // We only support good curves in WebCrypto. + // If that ever changes, check that a good one was chosen. + mSignatureAlg = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; + *aAuthType = ssl_kea_ecdh; + } else { + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } - virtual void Resolve() override { - // Make copies of the private key and certificate, otherwise, when this - // object is deleted, the structures they reference will be deleted too. - UniqueSECKEYPrivateKey key = mKeyPair->mPrivateKey->GetPrivateKey(); - CERTCertificate* cert = CERT_DupCertificate(mCertificate.get()); - RefPtr result = - new RTCCertificate(mResultPromise->GetParentObject(), key.release(), - cert, mAuthType, mExpires); - mResultPromise->MaybeResolve(result); - } -}; - -static PRTime ReadExpires(JSContext* aCx, const ObjectOrString& aOptions, - ErrorResult& aRv) { - // This conversion might fail, but we don't really care; use the default. - // If this isn't an object, or it doesn't coerce into the right type, - // then we won't get the |expires| value. Either will be caught later. - RTCCertificateExpiration expiration; - if (!aOptions.IsObject()) { - return EXPIRATION_DEFAULT; - } - JS::Rooted value(aCx, JS::ObjectValue(*aOptions.GetAsObject())); - if (!expiration.Init(aCx, value)) { - aRv.NoteJSContextException(aCx); - return 0; - } + return NS_OK; +} - if (!expiration.mExpires.WasPassed()) { - return EXPIRATION_DEFAULT; - } - static const uint64_t max = - static_cast(EXPIRATION_MAX / PR_USEC_PER_MSEC); - if (expiration.mExpires.Value() > max) { - return EXPIRATION_MAX; - } - return static_cast(expiration.mExpires.Value() * PR_USEC_PER_MSEC); +RefPtr RTCCertificateMetadata::Generate( + nsCOMPtr aCertService) { + return aCertService->GenerateCertificate(mParam, mExpires, mMechanism, + mSignatureAlg); } -already_AddRefed RTCCertificate::GenerateCertificate( +already_AddRefed RTCCertificate::Generate( const GlobalObject& aGlobal, const ObjectOrString& aOptions, - ErrorResult& aRv, JS::Compartment* aCompartment) { + ErrorResult& aRv) { nsIGlobalObject* global = xpc::NativeGlobal(aGlobal.Get()); - RefPtr p = Promise::Create(global, aRv); + RefPtr resultPromise = Promise::Create(global, aRv); if (aRv.Failed()) { return nullptr; } - Sequence usages; - if (!usages.AppendElement(u"sign"_ns, fallible)) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = mData.Init(aGlobal.Context(), aOptions, &mAuthType, aRv); + if (NS_FAILED(rv)) { + // webrtc-pc says to throw NotSupportedError if we have passed "an + // algorithm that the user agent cannot or will not use to generate a + // certificate". This catches these cases. + if (!aRv.Failed()) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + } return nullptr; } - PRTime expires = ReadExpires(aGlobal.Context(), aOptions, aRv); - if (aRv.Failed()) { + mCertService = do_GetService("@mozilla.org/rtccert/service;1"); + if (!mCertService) { + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); return nullptr; } - RefPtr task = new GenerateRTCCertificateTask( - global, aGlobal.Context(), aOptions, usages, expires); - task->DispatchWithPromise(p); - return p.forget(); -} - -RTCCertificate::RTCCertificate(nsIGlobalObject* aGlobal) - : mGlobal(aGlobal), - mPrivateKey(nullptr), - mCertificate(nullptr), - mAuthType(ssl_kea_null), - mExpires(0) {} - -RTCCertificate::RTCCertificate(nsIGlobalObject* aGlobal, - SECKEYPrivateKey* aPrivateKey, - CERTCertificate* aCertificate, - SSLKEAType aAuthType, PRTime aExpires) - : mGlobal(aGlobal), - mPrivateKey(aPrivateKey), - mCertificate(aCertificate), - mAuthType(aAuthType), - mExpires(aExpires) {} + + mData.Generate(mCertService) + ->Then( + GetCurrentSerialEventTarget(), __func__, + [s = RefPtr{this}, this, + resultPromise](const CertFingerprint& aResult) { + mCertFingerprint = aResult; + mCertService->GetCertificate(mCertFingerprint) + ->Then( + GetCurrentSerialEventTarget(), __func__, + [self = RefPtr{s}, + resultPromise](UniquePtr&& aResult) mutable { + self->mCertificate = std::move(aResult->mCertificate); + self->mExpires = aResult->mExpires; + resultPromise->MaybeResolve(self); + }, + [self = RefPtr{s}, resultPromise](nsresult aError) { + resultPromise->MaybeReject(aError); + }); + }, + [s = RefPtr{this}, resultPromise](nsresult aError) { + resultPromise->MaybeReject(aError); + }); + + return resultPromise.forget(); +} + +already_AddRefed RTCCertificate::GenerateCertificate( + const GlobalObject& aGlobal, const ObjectOrString& aOptions, + ErrorResult& aRv, JS::Compartment* aCompartment) { + RefPtr cert = + new RTCCertificate(xpc::NativeGlobal(aGlobal.Get())); + return cert->Generate(aGlobal, aOptions, aRv); +} + +RTCCertificate::RTCCertificate(nsIGlobalObject* aGlobal) : mGlobal(aGlobal) {}; + +RTCCertificate::~RTCCertificate() { + /* TODO -> how to handle clone? + if (mCertService && mCertificate) { + mCertService->RemoveCertificate(mCertFingerprint); + } + */ +} RefPtr RTCCertificate::CreateDtlsIdentity() const { - if (!mPrivateKey || !mCertificate) { + if (!mCertificate) { return nullptr; } - UniqueSECKEYPrivateKey key(SECKEY_CopyPrivateKey(mPrivateKey.get())); - UniqueCERTCertificate cert(CERT_DupCertificate(mCertificate.get())); - RefPtr id = - new DtlsIdentity(std::move(key), std::move(cert), mAuthType); + RefPtr id = new DtlsIdentity(mCertFingerprint, mAuthType); return id; } @@ -344,17 +276,10 @@ JSObject* RTCCertificate::WrapObject(JSC return RTCCertificate_Binding::Wrap(aCx, this, aGivenProto); } -bool RTCCertificate::WritePrivateKey(JSStructuredCloneWriter* aWriter) const { - JsonWebKey jwk; - nsresult rv = CryptoKey::PrivateKeyToJwk(mPrivateKey.get(), jwk); - if (NS_FAILED(rv)) { - return false; - } - nsString json; - if (!jwk.ToJSON(json)) { - return false; - } - return StructuredCloneHolder::WriteString(aWriter, json); +bool RTCCertificate::WriteCertificateFingerprint( + JSStructuredCloneWriter* aWriter) const { + return JS_WriteBytes(aWriter, mCertFingerprint.mHash, + CertFingerprint::sHashByteLen); } bool RTCCertificate::WriteCertificate(JSStructuredCloneWriter* aWriter) const { @@ -370,27 +295,23 @@ bool RTCCertificate::WriteCertificate(JS bool RTCCertificate::WriteStructuredClone( JSContext* aCx, JSStructuredCloneWriter* aWriter) const { - if (!mPrivateKey || !mCertificate) { + if (!mCertificate) { return false; } return JS_WriteUint32Pair(aWriter, RTCCERTIFICATE_SC_VERSION, mAuthType) && JS_WriteUint32Pair(aWriter, (mExpires >> 32) & 0xffffffff, mExpires & 0xffffffff) && - WritePrivateKey(aWriter) && WriteCertificate(aWriter); + WriteCertificateFingerprint(aWriter) && WriteCertificate(aWriter); } -bool RTCCertificate::ReadPrivateKey(JSStructuredCloneReader* aReader) { - nsString json; - if (!StructuredCloneHolder::ReadString(aReader, json)) { - return false; - } - JsonWebKey jwk; - if (!jwk.Init(json)) { +bool RTCCertificate::ReadCertificateFingerprint( + JSStructuredCloneReader* aReader) { + if (!JS_ReadBytes(aReader, mCertFingerprint.mHash, + CertFingerprint::sHashByteLen)) { return false; } - mPrivateKey = CryptoKey::PrivateKeyFromJwk(jwk); - return !!mPrivateKey; + return true; } bool RTCCertificate::ReadCertificate(JSStructuredCloneReader* aReader) { @@ -428,7 +349,8 @@ already_AddRefed RTCCert } cert->mExpires = static_cast(high) << 32 | low; - if (!cert->ReadPrivateKey(aReader) || !cert->ReadCertificate(aReader)) { + if (!cert->ReadCertificateFingerprint(aReader) || + !cert->ReadCertificate(aReader)) { return nullptr; } diff -up firefox-128.2.0/dom/media/webrtc/RTCCertificate.h.webrtc firefox-128.2.0/dom/media/webrtc/RTCCertificate.h --- firefox-128.2.0/dom/media/webrtc/RTCCertificate.h.webrtc 2024-08-26 16:23:35.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/RTCCertificate.h 2024-09-30 21:41:07.649369081 +0200 @@ -15,7 +15,11 @@ #include "mozilla/AlreadyAddRefed.h" #include "mozilla/Assertions.h" #include "mozilla/RefPtr.h" +#include "mozilla/dom/SubtleCryptoBinding.h" +#include "mozilla/MozPromise.h" +#include "mozilla/dom/RTCCertService.h" #include "nsCycleCollectionParticipant.h" +#include "nsICancelableRunnable.h" #include "nsIGlobalObject.h" #include "nsISupports.h" #include "nsWrapperCache.h" @@ -41,6 +45,26 @@ class GlobalObject; class ObjectOrString; class Promise; +class RTCCertificateMetadata { + public: + RTCCertificateMetadata(); + + nsresult Init(JSContext* aCx, const ObjectOrString& aAlgorithm, + SSLKEAType* aAuthType, ErrorResult& aRv); + RefPtr Generate( + nsCOMPtr aCertService); + + private: + nsTArray mParam; + PRTime mExpires; + SECOidTag mSignatureAlg; + UniquePLArenaPool mArena; + CK_MECHANISM_TYPE mMechanism; + PK11RSAGenParams mRsaParams; + nsString mNamedCurve; + nsString mAlgName; +}; + class RTCCertificate final : public nsISupports, public nsWrapperCache { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -52,9 +76,6 @@ class RTCCertificate final : public nsIS ErrorResult& aRv, JS::Compartment* aCompartment = nullptr); explicit RTCCertificate(nsIGlobalObject* aGlobal); - RTCCertificate(nsIGlobalObject* aGlobal, SECKEYPrivateKey* aPrivateKey, - CERTCertificate* aCertificate, SSLKEAType aAuthType, - PRTime aExpires); nsIGlobalObject* GetParentObject() const { return mGlobal; } virtual JSObject* WrapObject(JSContext* aCx, @@ -76,20 +97,29 @@ class RTCCertificate final : public nsIS JSStructuredCloneReader* aReader); private: - ~RTCCertificate() = default; + // TODO: cert ref counts? -> clone = remove? + ~RTCCertificate(); void operator=(const RTCCertificate&) = delete; RTCCertificate(const RTCCertificate&) = delete; + already_AddRefed Generate(const GlobalObject& aGlobal, + const ObjectOrString& aOptions, + ErrorResult& aRv); + bool ReadCertificate(JSStructuredCloneReader* aReader); - bool ReadPrivateKey(JSStructuredCloneReader* aReader); + bool ReadCertificateFingerprint(JSStructuredCloneReader* aReader); bool WriteCertificate(JSStructuredCloneWriter* aWriter) const; - bool WritePrivateKey(JSStructuredCloneWriter* aWriter) const; + bool WriteCertificateFingerprint(JSStructuredCloneWriter* aWriter) const; RefPtr mGlobal; - UniqueSECKEYPrivateKey mPrivateKey; + CertFingerprint mCertFingerprint; + + RTCCertificateMetadata mData; + + nsCOMPtr mCertService; UniqueCERTCertificate mCertificate; - SSLKEAType mAuthType; - PRTime mExpires; + SSLKEAType mAuthType = ssl_kea_null; + PRTime mExpires = 0; }; } // namespace dom diff -up firefox-128.2.0/dom/media/webrtc/RTCCertService.cpp.webrtc firefox-128.2.0/dom/media/webrtc/RTCCertService.cpp --- firefox-128.2.0/dom/media/webrtc/RTCCertService.cpp.webrtc 2024-09-30 21:41:07.648369048 +0200 +++ firefox-128.2.0/dom/media/webrtc/RTCCertService.cpp 2024-09-30 21:41:07.648369048 +0200 @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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 "RTCCertService.h" +#include "mozilla/net/SocketProcessBridgeChild.h" +#include "mozilla/ipc/BackgroundChild.h" +#include "mozilla/ipc/Endpoint.h" +#include "mozilla/ipc/PBackgroundChild.h" + +namespace mozilla::dom { + +NS_IMPL_ISUPPORTS(RTCCertService, nsIRTCCertService) + +already_AddRefed NewRTCCertService() { + nsCOMPtr certService(new RTCCertService()); + certService->Initialize(); + return certService.forget(); +} + +void RTCCertService::Initialize() { + using EndpointPromise = + MozPromise, + nsCString, true>; + mInitPromise = + net::SocketProcessBridgeChild::GetSocketProcessBridge() + ->Then( + GetCurrentSerialEventTarget(), __func__, + [](const RefPtr& aBridge) { + mozilla::ipc::Endpoint + parentEndpoint; + mozilla::ipc::Endpoint + childEndpoint; + + mozilla::dom::PRTCCertServiceTransaction::CreateEndpoints( + &parentEndpoint, &childEndpoint); + + if (!aBridge || !aBridge->SendInitRTCCertServiceTransaction( + std::move(parentEndpoint))) { + NS_WARNING( + "RTCCertService async init failed! Webrtc " + "networking " + "will not work!"); + return EndpointPromise::CreateAndReject( + nsCString("SendInitRTCCertServiceTransaction failed!"), + __func__); + } + return EndpointPromise::CreateAndResolve( + std::move(childEndpoint), __func__); + }, + [](const nsCString& aError) { + return EndpointPromise::CreateAndReject(aError, __func__); + }) + ->Then( + GetCurrentSerialEventTarget(), __func__, + [this, self = RefPtr(this)]( + mozilla::ipc::Endpoint&& + aEndpoint) { + RefPtr child = + new RTCCertServiceTransactionChild(); + aEndpoint.Bind(child); + mChild = child; + + return InitPromise::CreateAndResolve(true, __func__); + }, + [=](const nsCString& aError) { + NS_WARNING( + "RTCCertService async init failed! Webrtc " + "networking " + "will not work!"); + return InitPromise::CreateAndReject(aError, __func__); + }); +} + +RefPtr RTCCertService::GenerateCertificate( + const nsTArray& aParam, PRTime aExpires, uint32_t aMechanism, + uint32_t aSignatureAlg) { + return mInitPromise->Then( + GetCurrentSerialEventTarget(), __func__, + [self = RefPtr(this), this, param = aParam.Clone(), + aExpires, aMechanism, aSignatureAlg](bool /* dummy */) { + if (!mChild) { + return RTCCertFingerprintPromise::CreateAndReject(NS_ERROR_FAILURE, + __func__); + } + RefPtr promise = + mChild + ->SendGenerateCertificate(param, aExpires, aMechanism, + aSignatureAlg) + ->Then( + GetCurrentSerialEventTarget(), __func__, + [](CertFingerprint&& aCertFingerprint) { + return RTCCertFingerprintPromise::CreateAndResolve( + std::move(aCertFingerprint), __func__); + }, + [](mozilla::ipc::ResponseRejectReason aReason) { + return RTCCertFingerprintPromise::CreateAndReject( + NS_ERROR_FAILURE, __func__); + }); + return promise; + }, + [](const nsCString& aError) { + return RTCCertFingerprintPromise::CreateAndReject(NS_ERROR_FAILURE, + __func__); + }); +} + +void RTCCertService::RemoveCertificate( + const mozilla::dom::CertFingerprint aCertFingerprint) { + mInitPromise->Then( + GetCurrentSerialEventTarget(), __func__, + [self = RefPtr(this), this, + aCertFingerprint](bool /* dummy */) { + if (mChild) { + mChild->SendRemoveCertificate(aCertFingerprint); + } + }, + [](const nsCString& aError) {}); +} + +RefPtr RTCCertService::GetCertificate( + const CertFingerprint aCertFingerprint) { + return mInitPromise->Then( + GetCurrentSerialEventTarget(), __func__, + [self = RefPtr(this), this, + aCertFingerprint](bool /* dummy */) { + if (!mChild) { + return RTCCertificatePromise::CreateAndReject(NS_ERROR_FAILURE, + __func__); + } + RefPtr promise = + mChild->SendGetCertificate(aCertFingerprint) + ->Then( + GetCurrentSerialEventTarget(), __func__, + [](const CertDataIPC& aCertDataIPC) { + return RTCCertificatePromise::CreateAndResolve( + MakeUnique(&aCertDataIPC), __func__); + }, + + [](mozilla::ipc::ResponseRejectReason aReason) { + return RTCCertificatePromise::CreateAndReject( + NS_ERROR_FAILURE, __func__); + }); + return promise; + }, + [](const nsCString& aError) { + return RTCCertificatePromise::CreateAndReject(NS_ERROR_FAILURE, + __func__); + }); +} + +} // namespace mozilla::dom diff -up firefox-128.2.0/dom/media/webrtc/RTCCertServiceData.cpp.webrtc firefox-128.2.0/dom/media/webrtc/RTCCertServiceData.cpp --- firefox-128.2.0/dom/media/webrtc/RTCCertServiceData.cpp.webrtc 2024-09-30 21:41:07.648369048 +0200 +++ firefox-128.2.0/dom/media/webrtc/RTCCertServiceData.cpp 2024-09-30 21:41:07.648369048 +0200 @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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 "RTCCertServiceData.h" +#include "cert.h" +#include "mozpkix/nss_scoped_ptrs.h" +#include "sslerr.h" + +namespace mozilla::dom { + +CertFingerprint::CertFingerprint(const nsTArray& aCertFingerprint) { + MOZ_ASSERT(aCertFingerprint.Length() == sHashByteLen); + memcpy(mHash, const_cast(aCertFingerprint.Elements()), + static_cast(aCertFingerprint.Length())); +} + +CertFingerprint::operator nsTArray() { + nsTArray ret; + ret.AppendElements(reinterpret_cast(mHash), sHashByteLen); + return ret; +} + +bool CertFingerprint::Match(const CertFingerprint* aCertFingerprint) { + return mHash[0] == aCertFingerprint->mHash[0] && + mHash[1] == aCertFingerprint->mHash[1]; +} + +CertDataIPC::CertDataIPC(const CertData* aCertData) { + mExpires = aCertData->mExpires; + mCertificate.AppendElements(aCertData->mCertificate->derCert.data, + aCertData->mCertificate->derCert.len); +} + +CertData::CertData(const CertDataIPC* aCertDataIPC) { + SECItem certDer = { + siBuffer, const_cast(aCertDataIPC->mCertificate.Elements()), + static_cast(aCertDataIPC->mCertificate.Length())}; + UniqueCERTCertificate cert(CERT_NewTempCertificate( + CERT_GetDefaultCertDB(), &certDer, nullptr, true, true)); + mCertificate = std::move(cert); + mExpires = aCertDataIPC->mExpires; +} + +void SerializeRSAParam(nsTArray* aParams, + PK11RSAGenParams* aRsaParams) { + aParams->AppendElements(reinterpret_cast(aRsaParams), + sizeof(*aRsaParams)); +} + +PK11RSAGenParams DeserializeRSAParam(nsTArray* aParams) { + MOZ_ASSERT(aParams->Length() <= sizeof(PK11RSAGenParams)); + return *(reinterpret_cast(aParams->Elements())); +} + +bool SerializeECParams(nsTArray* aParams, SECItem* aECParams) { + if (!aECParams) { + return false; + } + aParams->AppendElements(reinterpret_cast(aECParams->data), + aECParams->len); + return true; +} + +SECItem* DeserializeECParams(nsTArray* aParams) { + SECItem* ret = ::SECITEM_AllocItem(nullptr, nullptr, 0); + SECItem it = {siBuffer, reinterpret_cast(aParams->Elements()), + static_cast(aParams->Length())}; + if (::SECITEM_CopyItem(nullptr, ret, &it) != SECSuccess) { + return nullptr; + } + return ret; +} + +} // namespace mozilla::dom diff -up firefox-128.2.0/dom/media/webrtc/RTCCertServiceData.h.webrtc firefox-128.2.0/dom/media/webrtc/RTCCertServiceData.h --- firefox-128.2.0/dom/media/webrtc/RTCCertServiceData.h.webrtc 2024-09-30 21:41:07.649369081 +0200 +++ firefox-128.2.0/dom/media/webrtc/RTCCertServiceData.h 2024-09-30 21:41:07.649369081 +0200 @@ -0,0 +1,105 @@ +/* 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_dom_RTCCertServiceGlobal_h_ +#define mozilla_dom_RTCCertServiceGlobal_h_ + +#include "ScopedNSSTypes.h" +#include "ipc/IPCMessageUtils.h" +#include "mozilla/ipc/IPDLParamTraits.h" +#include "mozilla/MozPromise.h" + +namespace mozilla { +namespace dom { + +struct CertFingerprint { + CertFingerprint() = default; + explicit CertFingerprint(const nsTArray& aCertFingerprint); + operator nsTArray(); + + bool Match(const struct CertFingerprint* aCertFingerprint); + unsigned char* AsChar() { return reinterpret_cast(mHash); } + + public: + const static size_t sHashByteLen = 16; + uint64_t mHash[2]; +}; + +struct CertData; +struct CertDataIPC { + CertDataIPC() = default; + explicit CertDataIPC(const CertData* aCertData); + + public: + nsTArray mCertificate; + PRTime mExpires; +}; + +struct CertData { + CertData(UniqueCERTCertificate aCertificate, PRTime aExpires) + : mCertificate(std::move(aCertificate)), mExpires(aExpires) {} + explicit CertData(const CertDataIPC* aCertDataIPC); + + // Don't copy CertData + CertData(const CertData&) = delete; + CertData& operator=(const CertData&) = delete; + + public: + UniqueCERTCertificate mCertificate; + PRTime mExpires; +}; + +using RTCCertFingerprintPromise = + MozPromise; +using RTCCertificatePromise = + MozPromise, nsresult, /* IsExclusive = */ true>; + +void SerializeRSAParam(nsTArray* aParams, + PK11RSAGenParams* aRsaParams); +PK11RSAGenParams DeserializeRSAParam(nsTArray* aParams); + +bool SerializeECParams(nsTArray* aParams, SECItem* aECParams); +SECItem* DeserializeECParams(nsTArray* aParams); +} // namespace dom + +namespace ipc { +template <> +struct IPDLParamTraits { + typedef dom::CertFingerprint paramType; + static void Write(IPC::MessageWriter* aWriter, ipc::IProtocol* aActor, + const paramType& aVar) { + WriteIPDLParam(aWriter, aActor, aVar.mHash[0]); + WriteIPDLParam(aWriter, aActor, aVar.mHash[1]); + } + static bool Read(IPC::MessageReader* aReader, mozilla::ipc::IProtocol* aActor, + paramType* aVar) { + if (!ReadIPDLParam(aReader, aActor, aVar->mHash) || + !ReadIPDLParam(aReader, aActor, aVar->mHash + 1)) { + return false; + } + return true; + } +}; + +template <> +struct IPDLParamTraits { + typedef dom::CertDataIPC paramType; + static void Write(IPC::MessageWriter* aWriter, ipc::IProtocol* aActor, + const paramType& aVar) { + WriteIPDLParam(aWriter, aActor, aVar.mCertificate); + WriteIPDLParam(aWriter, aActor, aVar.mExpires); + } + static bool Read(IPC::MessageReader* aReader, mozilla::ipc::IProtocol* aActor, + paramType* aVar) { + if (!ReadIPDLParam(aReader, aActor, &aVar->mCertificate) || + !ReadIPDLParam(aReader, aActor, &aVar->mExpires)) { + return false; + } + return true; + } +}; +} // namespace ipc +} // namespace mozilla + +#endif // mozilla_dom_RTCCertServiceGlobal_h_ diff -up firefox-128.2.0/dom/media/webrtc/RTCCertService.h.webrtc firefox-128.2.0/dom/media/webrtc/RTCCertService.h --- firefox-128.2.0/dom/media/webrtc/RTCCertService.h.webrtc 2024-09-30 21:41:07.648369048 +0200 +++ firefox-128.2.0/dom/media/webrtc/RTCCertService.h 2024-09-30 21:41:07.648369048 +0200 @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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_dom_RTCCertService_h_ +#define mozilla_dom_RTCCertService_h_ + +#include "mozilla/dom/PRTCCertServiceTransactionChild.h" +#include "nsIRTCCertService.h" +#include "mozilla/RefPtr.h" + +namespace mozilla::dom { + +already_AddRefed NewRTCCertService(); + +class RTCCertServiceTransactionChild : public PRTCCertServiceTransactionChild { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RTCCertServiceTransactionChild); + + private: + ~RTCCertServiceTransactionChild() = default; +}; + +class RTCCertService final : public nsIRTCCertService { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIRTCCERTSERVICE + + RTCCertService() = default; + + private: + ~RTCCertService() = default; + + RefPtr mChild; + + // |mChild| can only be initted asynchronously, |mInitPromise| resolves + // when that happens. The |Then| calls make it convenient to dispatch API + // calls to main, which is a bonus. + // Init promise is not exclusive; this lets us call |Then| on it for every + // API call we get, instead of creating another promise each time. + typedef MozPromise InitPromise; + RefPtr mInitPromise; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_CertServiceChild_h diff -up firefox-128.2.0/dom/media/webrtc/RTCCertServiceParent.cpp.webrtc firefox-128.2.0/dom/media/webrtc/RTCCertServiceParent.cpp --- firefox-128.2.0/dom/media/webrtc/RTCCertServiceParent.cpp.webrtc 2024-09-30 21:41:07.649369081 +0200 +++ firefox-128.2.0/dom/media/webrtc/RTCCertServiceParent.cpp 2024-09-30 21:41:07.649369081 +0200 @@ -0,0 +1,353 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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 "RTCCertCache.h" +#include "RTCCertServiceParent.h" +#include "mozilla/ipc/PBackgroundParent.h" +#include "mozilla/ipc/BackgroundParent.h" + +#define ONE_DAY \ + PRTime(PR_USEC_PER_SEC) * PRTime(60) /*sec*/ \ + * PRTime(60) /*min*/ * PRTime(24) /*hours*/ +#define EXPIRATION_SLACK ONE_DAY + +namespace mozilla::dom { + +using RTCCertificateGeneratorPromise = + MozPromise, nsresult, + /* IsExclusive = */ true>; + +class RTCCertificateGenerator final : public CancelableRunnable { + public: + RTCCertificateGenerator(); + RefPtr Generate(nsTArray& aParam, + PRTime aExpires, + CK_MECHANISM_TYPE aMechanism, + SECOidTag aSignatureAlg); + + private: + ~RTCCertificateGenerator(); + + bool IsOnOriginalThread() { + return !mOriginalEventTarget || mOriginalEventTarget->IsOnCurrentThread(); + } + + nsresult GenerateKeys(); + nsresult GenerateCertificate(); + + NS_IMETHOD Run() override; + nsresult Cancel() override; + void Finish(); + + UniquePtr mGen; + + // Source data + void* mParam = nullptr; + PK11RSAGenParams mRsaParams; + SECItem* mCurveParams = nullptr; + CK_MECHANISM_TYPE mMechanism = 0; + SECOidTag mSignatureAlg = SEC_OID_UNKNOWN; + nsresult mCryptoResult = NS_OK; + + RefPtr mGenPromise; + nsCOMPtr mOriginalEventTarget; +}; + +const size_t RTCCertificateCommonNameLength = 16; + +nsresult RTCCertificateGenerator::GenerateKeys() { + UniquePK11SlotInfo slot(PK11_GetInternalSlot()); + MOZ_ASSERT(slot.get()); + + mGen->mPrivateKey = UniqueSECKEYPrivateKey(PK11_GenerateKeyPair( + slot.get(), mMechanism, mParam, TempPtrToSetter(&mGen->mPublicKey), + PR_FALSE, PR_TRUE, nullptr)); + + if (!mGen->mPrivateKey.get() || !mGen->mPublicKey.get()) { + return NS_ERROR_DOM_OPERATION_ERR; + } + + return NS_OK; +} + +static CERTName* GenerateRandomName(PK11SlotInfo* aSlot) { + uint8_t randomName[RTCCertificateCommonNameLength]; + SECStatus rv = + PK11_GenerateRandomOnSlot(aSlot, randomName, sizeof(randomName)); + if (rv != SECSuccess) { + return nullptr; + } + + char buf[sizeof(randomName) * 2 + 4]; + strncpy(buf, "CN=", 4); + for (size_t i = 0; i < sizeof(randomName); ++i) { + snprintf(&buf[i * 2 + 3], 3, "%.2x", randomName[i]); + } + buf[sizeof(buf) - 1] = '\0'; + + return CERT_AsciiToName(buf); +} + +nsresult RTCCertificateGenerator::GenerateCertificate() { + UniquePK11SlotInfo slot(PK11_GetInternalSlot()); + MOZ_ASSERT(slot.get()); + + UniqueCERTName subjectName(GenerateRandomName(slot.get())); + if (!subjectName) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + + UniqueCERTSubjectPublicKeyInfo spki( + SECKEY_CreateSubjectPublicKeyInfo(mGen->mPublicKey.get())); + if (!spki) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + + UniqueCERTCertificateRequest certreq( + CERT_CreateCertificateRequest(subjectName.get(), spki.get(), nullptr)); + if (!certreq) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + + PRTime now = PR_Now(); + PRTime notBefore = now - EXPIRATION_SLACK; + mGen->mExpires += now; + + UniqueCERTValidity validity(CERT_CreateValidity(notBefore, mGen->mExpires)); + if (!validity) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + + unsigned long serial; + // Note: This serial in principle could collide, but it's unlikely, and we + // don't expect anyone to be validating certificates anyway. + SECStatus rv = PK11_GenerateRandomOnSlot( + slot.get(), reinterpret_cast(&serial), sizeof(serial)); + if (rv != SECSuccess) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + + // NB: CERTCertificates created with CERT_CreateCertificate are not safe to + // use with other NSS functions like CERT_DupCertificate. The strategy + // here is to create a tbsCertificate ("to-be-signed certificate"), encode + // it, and sign it, resulting in a signed DER certificate that can be + // decoded into a CERTCertificate. + UniqueCERTCertificate tbsCertificate(CERT_CreateCertificate( + serial, subjectName.get(), validity.get(), certreq.get())); + if (!tbsCertificate) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + + MOZ_ASSERT(mSignatureAlg != SEC_OID_UNKNOWN); + PLArenaPool* arena = tbsCertificate->arena; + + rv = SECOID_SetAlgorithmID(arena, &tbsCertificate->signature, mSignatureAlg, + nullptr); + if (rv != SECSuccess) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + + // Set version to X509v3. + *(tbsCertificate->version.data) = SEC_CERTIFICATE_VERSION_3; + tbsCertificate->version.len = 1; + + SECItem innerDER = {siBuffer, nullptr, 0}; + if (!SEC_ASN1EncodeItem(arena, &innerDER, tbsCertificate.get(), + SEC_ASN1_GET(CERT_CertificateTemplate))) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + + SECItem* certDer = PORT_ArenaZNew(arena, SECItem); + if (!certDer) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + + rv = SEC_DerSignData(arena, certDer, innerDER.data, innerDER.len, + mGen->mPrivateKey.get(), mSignatureAlg); + if (rv != SECSuccess) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + + mGen->mCertificate.reset(CERT_NewTempCertificate( + CERT_GetDefaultCertDB(), certDer, nullptr, false, true)); + if (!mGen->mCertificate) { + return NS_ERROR_DOM_UNKNOWN_ERR; + } + + if (PK11_HashBuf(SEC_OID_MD5, mGen->mCertFingerprint.AsChar(), certDer->data, + AssertedCast(certDer->len)) != SECSuccess) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +RefPtr RTCCertificateGenerator::Generate( + nsTArray& aParam, PRTime aExpires, CK_MECHANISM_TYPE aMechanism, + SECOidTag aSignatureAlg) { + mGenPromise = MakeRefPtr(__func__); + + mGen = MakeUnique(); + mGen->mExpires = aExpires; + + mMechanism = aMechanism; + mSignatureAlg = aSignatureAlg; + + if (mMechanism == CKM_RSA_PKCS_KEY_PAIR_GEN) { + mRsaParams = DeserializeRSAParam(&aParam); + mParam = &mRsaParams; + } else if (mMechanism == CKM_EC_KEY_PAIR_GEN) { + mCurveParams = DeserializeECParams(&aParam); + mParam = mCurveParams; + } else { + mGenPromise->Reject(NS_ERROR_NOT_IMPLEMENTED, __func__); + return mGenPromise; + } + + // Store calling thread + mOriginalEventTarget = GetCurrentSerialEventTarget(); + + // dispatch to thread pool + if (!EnsureNSSInitializedChromeOrContent()) { + mGenPromise->Reject(NS_ERROR_FAILURE, __func__); + return mGenPromise; + } + + mCryptoResult = NS_DispatchBackgroundTask(this); + if (NS_FAILED(mCryptoResult)) { + mGenPromise->Reject(mCryptoResult, __func__); + return mGenPromise; + } + + return mGenPromise; +} + +RTCCertificateGenerator::RTCCertificateGenerator() + : CancelableRunnable("RTCCertificateGenerator") {} + +RTCCertificateGenerator::~RTCCertificateGenerator() { + if (mCurveParams) { + ::SECITEM_FreeItem(mCurveParams, PR_TRUE); + mCurveParams = nullptr; + } +} + +void RTCCertificateGenerator::Finish() { + MOZ_ASSERT(IsOnOriginalThread()); + + if (NS_FAILED(mCryptoResult)) { + mGenPromise->Reject(mCryptoResult, __func__); + } else { + mGenPromise->Resolve(std::move(mGen), __func__); + } + mGenPromise = nullptr; +} + +NS_IMETHODIMP +RTCCertificateGenerator::Run() { + // Run heavy crypto operations on the thread pool, off the original thread. + if (!IsOnOriginalThread()) { + mCryptoResult = GenerateKeys(); + if (NS_SUCCEEDED(mCryptoResult)) { + mCryptoResult = GenerateCertificate(); + } + + // Back to the original thread, i.e. continue below. + mOriginalEventTarget->Dispatch(this, NS_DISPATCH_NORMAL); + return NS_OK; + } + + Finish(); + return NS_OK; +} + +nsresult RTCCertificateGenerator::Cancel() { + MOZ_ASSERT(IsOnOriginalThread()); + mCryptoResult = NS_BINDING_ABORTED; + Finish(); + return NS_OK; +} + +RefPtr RTCCertServiceParent::GenerateCertificate( + nsTArray& aParam, PRTime aExpires, uint32_t aMechanism, + uint32_t aSignatureAlg) { + RefPtr resultPromise = + MakeRefPtr(__func__); + + RefPtr gen = new RTCCertificateGenerator(); + gen->Generate(aParam, aExpires, aMechanism, + static_cast(aSignatureAlg)) + ->Then(GetCurrentSerialEventTarget(), __func__, + [s = RefPtr{this}, resultPromise]( + RTCCertificateGeneratorPromise::ResolveOrRejectValue&& + aValue) mutable { + if (aValue.IsResolve()) { + UniquePtr genCert = + std::move(aValue.ResolveValue()); + CertFingerprint certFingerprint = genCert->mCertFingerprint; + RTCCertCache::CacheCert(std::move(genCert)); + resultPromise->Resolve(certFingerprint, __func__); + } else if (aValue.IsReject()) { + resultPromise->Reject(aValue.RejectValue(), __func__); + } + }); + + return resultPromise; +} + +RefPtr RTCCertServiceParent::GetCertificate( + const CertFingerprint aCertFingerprint) { + if (GeneratedCertificate* cert = RTCCertCache::LookupCert(aCertFingerprint)) { + auto data = MakeUnique( + UniqueCERTCertificate(CERT_DupCertificate(cert->mCertificate.get())), + cert->mExpires); + return RTCCertificatePromise::CreateAndResolve(std::move(data), __func__); + } + return RTCCertificatePromise::CreateAndReject(NS_ERROR_FAILURE, __func__); +} + +mozilla::ipc::IPCResult RTCCertServiceParent::RecvGenerateCertificate( + nsTArray&& aParam, const PRTime& aExpires, + const uint32_t& aMechanism, const uint32_t& aSignatureAlg, + GenerateCertificateResolver&& aResolve) { + GenerateCertificate(aParam, aExpires, aMechanism, aSignatureAlg) + ->Then(GetCurrentSerialEventTarget(), __func__, + [aResolve = std::move(aResolve)]( + const dom::RTCCertFingerprintPromise::ResolveOrRejectValue& + aResult) { + if (aResult.IsResolve()) { + aResolve(aResult.ResolveValue()); + } else { + aResolve(CertFingerprint()); + } + }); + return IPC_OK(); +} + +mozilla::ipc::IPCResult RTCCertServiceParent::RecvRemoveCertificate( + const CertFingerprint& aCertFingerprint) { + RTCCertCache::RemoveCert(aCertFingerprint); + return IPC_OK(); +} + +mozilla::ipc::IPCResult RTCCertServiceParent::RecvGetCertificate( + const CertFingerprint& aCertFingerprint, + GetCertificateResolver&& aResolve) { + GetCertificate(aCertFingerprint) + ->Then( + GetCurrentSerialEventTarget(), __func__, + [aResolve = std::move(aResolve)]( + const dom::RTCCertificatePromise::ResolveOrRejectValue& aResult) { + if (aResult.IsResolve()) { + aResolve(CertDataIPC(aResult.ResolveValue().get())); + } else { + aResolve(CertDataIPC()); + } + }); + return IPC_OK(); +} + +} // namespace mozilla::dom diff -up firefox-128.2.0/dom/media/webrtc/RTCCertServiceParent.h.webrtc firefox-128.2.0/dom/media/webrtc/RTCCertServiceParent.h --- firefox-128.2.0/dom/media/webrtc/RTCCertServiceParent.h.webrtc 2024-09-30 21:41:07.649369081 +0200 +++ firefox-128.2.0/dom/media/webrtc/RTCCertServiceParent.h 2024-09-30 21:41:07.649369081 +0200 @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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_dom_CertServiceParent_h +#define mozilla_dom_CertServiceParent_h + +#include "mozilla/dom/PRTCCertServiceTransactionParent.h" +#include "mozilla/dom/RTCCertServiceData.h" + +namespace mozilla::dom { + +class RTCCertServiceParent final : public PRTCCertServiceTransactionParent { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RTCCertServiceParent); + RTCCertServiceParent() = default; + + mozilla::ipc::IPCResult RecvGenerateCertificate( + nsTArray&& aParam, const PRTime& aExpires, + const uint32_t& aMechanism, const uint32_t& aSignatureAlg, + GenerateCertificateResolver&& aResolve); + mozilla::ipc::IPCResult RecvRemoveCertificate( + const CertFingerprint& aCertFingerprint); + mozilla::ipc::IPCResult RecvGetCertificate( + const CertFingerprint& aCertFingerprint, + GetCertificateResolver&& aResolve); + + RefPtr GenerateCertificate( + nsTArray& aParam, PRTime aExpires, uint32_t aMechanism, + uint32_t aSignatureAlg); + RefPtr GetCertificate( + const CertFingerprint aCertFingerprint); + + private: + ~RTCCertServiceParent() = default; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_CertServiceTransactionParent_h diff -up firefox-128.2.0/dom/media/webrtc/transport/dtlsidentity.cpp.webrtc firefox-128.2.0/dom/media/webrtc/transport/dtlsidentity.cpp --- firefox-128.2.0/dom/media/webrtc/transport/dtlsidentity.cpp.webrtc 2024-08-26 16:23:35.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/transport/dtlsidentity.cpp 2024-09-30 21:41:07.651369147 +0200 @@ -17,136 +17,19 @@ #include "sslerr.h" #include "mozilla/Sprintf.h" +#include "mozilla/dom/RTCCertCache.h" 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())); - if (!derPki) { - return NS_ERROR_FAILURE; - } - - aKeyDer->AppendElements(derPki->data, derPki->len); - aCertDer->AppendElements(cert_->derCert.data, cert_->derCert.len); +nsresult DtlsIdentity::Serialize(nsTArray& certFingerprint) { + certFingerprint = cert_fingerprint_; return NS_OK; } /* static */ RefPtr DtlsIdentity::Deserialize( - const nsTArray& aKeyDer, const nsTArray& aCertDer, - SSLKEAType authType) { - SECItem certDer = {siBuffer, const_cast(aCertDer.Elements()), - static_cast(aCertDer.Length())}; - UniqueCERTCertificate cert(CERT_NewTempCertificate( - CERT_GetDefaultCertDB(), &certDer, nullptr, true, true)); - - SECItem derPKI = {siBuffer, const_cast(aKeyDer.Elements()), - static_cast(aKeyDer.Length())}; - - SECKEYPrivateKey* privateKey; - if (UnwrapPrivateKeyInfoWithEmptyPassword(&derPKI, cert, &privateKey) != - SECSuccess) { - MOZ_ASSERT(false); - return nullptr; - } - - return new DtlsIdentity(UniqueSECKEYPrivateKey(privateKey), std::move(cert), - authType); + const nsTArray& certFingerprint, SSLKEAType authType) { + return new DtlsIdentity(dom::CertFingerprint(certFingerprint), authType); } RefPtr DtlsIdentity::Generate() { @@ -283,7 +166,7 @@ RefPtr DtlsIdentity::Gener constexpr nsLiteralCString DtlsIdentity::DEFAULT_HASH_ALGORITHM; -nsresult DtlsIdentity::ComputeFingerprint(DtlsDigest* digest) const { +nsresult DtlsIdentity::ComputeFingerprint(DtlsDigest* digest) { const UniqueCERTCertificate& c = cert(); MOZ_ASSERT(c); @@ -328,4 +211,28 @@ nsresult DtlsIdentity::ComputeFingerprin return NS_OK; } +const UniqueCERTCertificate& DtlsIdentity::cert() { + if (!cert_) { + dom::GeneratedCertificate* genCert = + dom::RTCCertCache::LookupCert(cert_fingerprint_); + if (genCert) { + cert_ = UniqueCERTCertificate( + CERT_DupCertificate(genCert->mCertificate.get())); + } + } + return cert_; +} + +const UniqueSECKEYPrivateKey& DtlsIdentity::privkey() { + if (!private_key_) { + dom::GeneratedCertificate* genCert = + dom::RTCCertCache::LookupCert(cert_fingerprint_); + if (genCert) { + private_key_ = UniqueSECKEYPrivateKey( + SECKEY_CopyPrivateKey(genCert->mPrivateKey.get())); + } + } + return private_key_; +} + } // namespace mozilla diff -up firefox-128.2.0/dom/media/webrtc/transport/dtlsidentity.h.webrtc firefox-128.2.0/dom/media/webrtc/transport/dtlsidentity.h --- firefox-128.2.0/dom/media/webrtc/transport/dtlsidentity.h.webrtc 2024-08-26 16:23:35.000000000 +0200 +++ firefox-128.2.0/dom/media/webrtc/transport/dtlsidentity.h 2024-09-30 21:41:07.651369147 +0200 @@ -10,6 +10,7 @@ #include #include "ScopedNSSTypes.h" +#include "mozilla/dom/RTCCertCache.h" #include "m_cpp_utils.h" #include "mozilla/RefPtr.h" #include "nsISupportsImpl.h" @@ -58,14 +59,15 @@ class DtlsIdentity final { : private_key_(std::move(privkey)), cert_(std::move(cert)), auth_type_(authType) {} + DtlsIdentity(dom::CertFingerprint certFingerprint, SSLKEAType authType) + : cert_fingerprint_(certFingerprint), auth_type_(authType) {} // Allows serialization/deserialization; cannot write IPC serialization code // directly for DtlsIdentity, since IPC-able types need to be constructable // on the stack. - nsresult Serialize(nsTArray* aKeyDer, nsTArray* aCertDer); - static RefPtr Deserialize(const nsTArray& aKeyDer, - const nsTArray& aCertDer, - SSLKEAType authType); + nsresult Serialize(nsTArray& certFingerprint); + static RefPtr Deserialize( + const nsTArray& certFingerprint, SSLKEAType authType); // This is only for use in tests, or for external linkage. It makes a (bad) // instance of this class. @@ -73,15 +75,15 @@ class DtlsIdentity final { // These don't create copies or transfer ownership. If you want these to live // on, make a copy. - const UniqueCERTCertificate& cert() const { return cert_; } - const UniqueSECKEYPrivateKey& privkey() const { return private_key_; } + const UniqueCERTCertificate& cert(); + const UniqueSECKEYPrivateKey& privkey(); // Note: this uses SSLKEAType because that is what the libssl API requires. // This is a giant confusing mess, but libssl indexes certificates based on a // key exchange type, not authentication type (as you might have reasonably // expected). SSLKEAType auth_type() const { return auth_type_; } - nsresult ComputeFingerprint(DtlsDigest* digest) const; + nsresult ComputeFingerprint(DtlsDigest* digest); static nsresult ComputeFingerprint(const UniqueCERTCertificate& cert, DtlsDigest* digest); @@ -94,6 +96,7 @@ class DtlsIdentity final { ~DtlsIdentity() = default; DISALLOW_COPY_ASSIGN(DtlsIdentity); + dom::CertFingerprint cert_fingerprint_; UniqueSECKEYPrivateKey private_key_; UniqueCERTCertificate cert_; SSLKEAType auth_type_; diff -up firefox-128.2.0/ipc/glue/BackgroundParentImpl.cpp.webrtc firefox-128.2.0/ipc/glue/BackgroundParentImpl.cpp --- firefox-128.2.0/ipc/glue/BackgroundParentImpl.cpp.webrtc 2024-08-26 16:23:36.000000000 +0200 +++ firefox-128.2.0/ipc/glue/BackgroundParentImpl.cpp 2024-09-30 21:41:07.651369147 +0200 @@ -57,6 +57,7 @@ #include "mozilla/dom/quota/QuotaParent.h" #include "mozilla/dom/simpledb/ActorsParent.h" #include "mozilla/dom/VsyncParent.h" +#include "mozilla/dom/PRTCCertServiceTransactionParent.h" #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/Endpoint.h" diff -up firefox-128.2.0/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp.webrtc firefox-128.2.0/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp --- firefox-128.2.0/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp.webrtc 2024-08-26 16:23:42.000000000 +0200 +++ firefox-128.2.0/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp 2024-09-30 21:41:07.651369147 +0200 @@ -197,13 +197,15 @@ class LoopbackTransport : public MediaTr // this up internally const nsTArray& aStunAddrs) override {} - void ActivateTransport( - const std::string& aTransportId, const std::string& aLocalUfrag, - const std::string& aLocalPwd, size_t aComponentCount, - const std::string& aUfrag, const std::string& aPassword, - const nsTArray& aKeyDer, const nsTArray& aCertDer, - SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests, - bool aPrivacyRequested) override {} + void ActivateTransport(const std::string& aTransportId, + const std::string& aLocalUfrag, + const std::string& aLocalPwd, size_t aComponentCount, + const std::string& aUfrag, + const std::string& aPassword, + const nsTArray& aCertFingerprint, + SSLKEAType aAuthType, bool aDtlsClient, + const DtlsDigestList& aDigests, + bool aPrivacyRequested) override {} void RemoveTransportsExcept( const std::set& aTransportIds) override {} diff -up firefox-128.2.0/netwerk/ipc/PSocketProcessBridge.ipdl.webrtc firefox-128.2.0/netwerk/ipc/PSocketProcessBridge.ipdl --- firefox-128.2.0/netwerk/ipc/PSocketProcessBridge.ipdl.webrtc 2024-08-26 16:23:42.000000000 +0200 +++ firefox-128.2.0/netwerk/ipc/PSocketProcessBridge.ipdl 2024-09-30 21:41:07.651369147 +0200 @@ -10,6 +10,8 @@ include protocol PBackgroundDataBridge; include protocol PMediaTransport; #endif // MOZ_WEBRTC +include protocol PRTCCertServiceTransaction; + namespace mozilla { namespace net { @@ -42,6 +44,7 @@ parent: async InitMediaTransport(Endpoint aEndpoint); #endif // MOZ_WEBRTC + async InitRTCCertServiceTransaction(Endpoint aEndpoint); }; } diff -up firefox-128.2.0/netwerk/ipc/SocketProcessBridgeParent.cpp.webrtc firefox-128.2.0/netwerk/ipc/SocketProcessBridgeParent.cpp --- firefox-128.2.0/netwerk/ipc/SocketProcessBridgeParent.cpp.webrtc 2024-08-26 16:23:43.000000000 +0200 +++ firefox-128.2.0/netwerk/ipc/SocketProcessBridgeParent.cpp 2024-09-30 21:41:07.651369147 +0200 @@ -9,6 +9,7 @@ #ifdef MOZ_WEBRTC # include "mozilla/dom/MediaTransportParent.h" #endif +#include "mozilla/dom/RTCCertServiceParent.h" #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/ipc/Endpoint.h" #include "SocketProcessChild.h" @@ -83,6 +84,37 @@ mozilla::ipc::IPCResult SocketProcessBri } #endif +mozilla::ipc::IPCResult +SocketProcessBridgeParent::RecvInitRTCCertServiceTransaction( + mozilla::ipc::Endpoint&& + aEndpoint) { + LOG(("SocketProcessBridgeParent::RecvInitRTCCertServiceTransaction\n")); + + if (!aEndpoint.IsValid()) { + return IPC_FAIL(this, "Invalid endpoint"); + } + + if (!mMediaTransportTaskQueue) { + nsCOMPtr transportQueue; + if (NS_FAILED(NS_CreateBackgroundTaskQueue( + "MediaTransport", getter_AddRefs(transportQueue)))) { + return IPC_FAIL(this, "NS_CreateBackgroundTaskQueue failed"); + } + + mMediaTransportTaskQueue = std::move(transportQueue); + } + + mMediaTransportTaskQueue->Dispatch( + NS_NewRunnableFunction("BackgroundDataBridgeParent::Bind", + [endpoint = std::move(aEndpoint)]() mutable { + RefPtr actor = + new dom::RTCCertServiceParent(); + endpoint.Bind(actor); + })); + + return IPC_OK(); +} + void SocketProcessBridgeParent::ActorDestroy(ActorDestroyReason aReason) { // See bug 1846478. We might be able to remove this dispatch. GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction( diff -up firefox-128.2.0/netwerk/ipc/SocketProcessBridgeParent.h.webrtc firefox-128.2.0/netwerk/ipc/SocketProcessBridgeParent.h --- firefox-128.2.0/netwerk/ipc/SocketProcessBridgeParent.h.webrtc 2024-08-26 16:23:43.000000000 +0200 +++ firefox-128.2.0/netwerk/ipc/SocketProcessBridgeParent.h 2024-09-30 21:41:07.651369147 +0200 @@ -29,6 +29,9 @@ class SocketProcessBridgeParent final : Endpoint&& aEndpoint); #endif + mozilla::ipc::IPCResult RecvInitRTCCertServiceTransaction( + Endpoint&& aEndpoint); + void ActorDestroy(ActorDestroyReason aReason) override; private: diff -up firefox-128.2.0/third_party/libwebrtc/examples/androidtests/third_party/README.webrtc firefox-128.2.0/third_party/libwebrtc/examples/androidtests/third_party/README