firefox/webrtc-128.0.patch
Jan Horak d5a7f05712 Rebase to 140.3.0 ESR
Following changes were made during rebase:
Use gcc toolset 14 instead of 13
Fixed annocheck workaround and backported ensure kiosk mode
Removed disable-vsync-for-kiosk.patch
Update to 140 esr
Update bundled package list
Cleanup patches:
- remove unused patches
- fix patch versioning
- rename webrtc-128.0.patch to D225034.xxxx based on the merge request
Use system libraries for drm/gbm/pipewire
Update patch disabling PipeWire support
Backported fips patches
Enable system nss
Update nss versions
Added fixes for rhel9 from SE
Fix the system pipewire build
Update to 140.1.0
Cleanup and incorporating of SE changes
Fixing spec file
adding av1-else-condition-add.patch
fixing av1 disable patch
Fixed exceptionHandler patch
Update to 140.2.0
Removed bundled(cups) as long as it is not bundled
Changes related to rebase-140 of rhel-9.x(9.0, 9.2, 9.4) streams owned by SE
1.Added updated nss-3.112 in the Sources and .gitignore and updated its reference inside specfile
2.Add condition to not enable system_gbm, drm, pipewire as build was failing
3.Added handling for setting bundled_nss=1 for these streams,so that it used nss bundled nspr
changes related to rhel 8.x(2,4,6,8) and 7.9 version
Added fixes for missing translation and gnome kiosk
Update to 140.3.0 esr

Resolves: RHEL-114034
2025-09-18 14:48:56 +02:00

2359 lines
90 KiB
Diff

diff -up firefox-140.0/dom/crypto/WebCryptoTask.cpp.D225034.1750779491 firefox-140.0/dom/crypto/WebCryptoTask.cpp
--- firefox-140.0/dom/crypto/WebCryptoTask.cpp.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/crypto/WebCryptoTask.cpp 2025-06-26 12:19:09.532341457 +0200
@@ -120,60 +120,6 @@ enum TelemetryAlgorithm {
} \
}
-class ClearException {
- public:
- explicit ClearException(JSContext* aCx) : mCx(aCx) {}
-
- ~ClearException() { JS_ClearPendingException(mCx); }
-
- private:
- JSContext* mCx;
-};
-
-template <class OOS>
-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<JS::Value> value(aCx,
- JS::ObjectValue(*aAlgorithm.GetAsObject()));
- Algorithm alg;
-
- if (!alg.Init(aCx, value)) {
- return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
- }
-
- aName = alg.mName;
- }
-
- if (!NormalizeToken(aName, aName)) {
- return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
- }
-
- return NS_OK;
-}
-
-template <class T, class OOS>
-static nsresult Coerce(JSContext* aCx, T& aTarget, const OOS& aAlgorithm) {
- ClearException ce(aCx);
-
- if (!aAlgorithm.IsObject()) {
- return NS_ERROR_DOM_SYNTAX_ERR;
- }
-
- JS::Rooted<JS::Value> 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)) {
@@ -2488,6 +2434,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<nsString>& aKeyUsages);
+
+ protected:
+ UniquePLArenaPool mArena;
+ UniquePtr<CryptoKeyPair> 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;
+};
+
class DeriveX25519BitsTask : public ReturnArrayBufferViewTask {
public:
DeriveX25519BitsTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
diff -up firefox-140.0/dom/crypto/WebCryptoTask.h.D225034.1750779491 firefox-140.0/dom/crypto/WebCryptoTask.h
--- firefox-140.0/dom/crypto/WebCryptoTask.h.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/crypto/WebCryptoTask.h 2025-06-26 12:14:42.300401357 +0200
@@ -176,31 +176,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<nsString>& aKeyUsages);
-
- protected:
- UniquePLArenaPool mArena;
- UniquePtr<CryptoKeyPair> 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 <class OOS>
+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<JS::Value> 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 <class T, class OOS>
+nsresult Coerce(JSContext* aCx, T& aTarget, const OOS& aAlgorithm) {
+ ClearException ce(aCx);
+
+ if (!aAlgorithm.IsObject()) {
+ return NS_ERROR_DOM_SYNTAX_ERR;
+ }
+
+ JS::Rooted<JS::Value> 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-140.0/dom/media/webrtc/components.conf.D225034.1750779491 firefox-140.0/dom/media/webrtc/components.conf
--- firefox-140.0/dom/media/webrtc/components.conf.D225034.1750779491 2025-06-26 12:14:42.300775330 +0200
+++ firefox-140.0/dom/media/webrtc/components.conf 2025-06-26 12:14:42.300775330 +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-140.0/dom/media/webrtc/jsapi/MediaTransportHandler.cpp.D225034.1750779491 firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandler.cpp
--- firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandler.cpp.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandler.cpp 2025-06-26 12:14:42.301060154 +0200
@@ -104,13 +104,15 @@ class MediaTransportHandlerSTS : public
// via IPC anymore
const nsTArray<NrIceStunAddr>& 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<uint8_t>& aKeyDer, const nsTArray<uint8_t>& 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<uint8_t>& aCertFingerprint,
+ SSLKEAType aAuthType, bool aDtlsClient,
+ const DtlsDigestList& aDigests,
+ bool aPrivacyRequested) override;
void RemoveTransportsExcept(
const std::set<std::string>& aTransportIds) override;
@@ -804,14 +806,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<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer,
- SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests,
- bool aPrivacyRequested) {
+ const nsTArray<uint8_t>& 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<MediaTransportHandlerSTS>(this)]() {
if (!mIceCtx) {
return; // Probably due to XPCOM shutdown
@@ -819,7 +820,7 @@ void MediaTransportHandlerSTS::ActivateT
MOZ_ASSERT(aComponentCount);
RefPtr<DtlsIdentity> dtlsIdentity(
- DtlsIdentity::Deserialize(keyDer, certDer, aAuthType));
+ DtlsIdentity::Deserialize(aCertFingerprint, aAuthType));
if (!dtlsIdentity) {
MOZ_ASSERT(false);
return;
diff -up firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandler.h.D225034.1750779491 firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandler.h
--- firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandler.h.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandler.h 2025-06-26 12:14:42.301442663 +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<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer,
- SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests,
+ const nsTArray<uint8_t>& aCertFingerprint, SSLKEAType aAuthType,
+ bool aDtlsClient, const DtlsDigestList& aDigests,
bool aPrivacyRequested) = 0;
virtual void RemoveTransportsExcept(
diff -up firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp.D225034.1750779491 firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp
--- firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.cpp 2025-06-26 12:14:42.301675179 +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<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer,
- SSLKEAType aAuthType, bool aDtlsClient, const DtlsDigestList& aDigests,
- bool aPrivacyRequested) {
+ const nsTArray<uint8_t>& 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<MediaTransportHandlerIPC>(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-140.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.h.D225034.1750779491 firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.h
--- firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.h.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/jsapi/MediaTransportHandlerIPC.h 2025-06-26 12:14:42.301923105 +0200
@@ -49,13 +49,15 @@ class MediaTransportHandlerIPC final : p
// this up internally
const nsTArray<NrIceStunAddr>& 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<uint8_t>& aKeyDer, const nsTArray<uint8_t>& 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<uint8_t>& aCertFingerprint,
+ SSLKEAType aAuthType, bool aDtlsClient,
+ const DtlsDigestList& aDigests,
+ bool aPrivacyRequested) override;
void RemoveTransportsExcept(
const std::set<std::string>& aTransportIds) override;
diff -up firefox-140.0/dom/media/webrtc/jsapi/MediaTransportParent.cpp.D225034.1750779491 firefox-140.0/dom/media/webrtc/jsapi/MediaTransportParent.cpp
--- firefox-140.0/dom/media/webrtc/jsapi/MediaTransportParent.cpp.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/jsapi/MediaTransportParent.cpp 2025-06-26 12:14:42.302133961 +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<uint8_t>&& keyDer,
- nsTArray<uint8_t>&& certDer, const int& authType, const bool& dtlsClient,
- const DtlsDigestList& digests, const bool& privacyRequested) {
+ const string& remotePwd, nsTArray<uint8_t>&& 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<SSLKEAType>(authType), dtlsClient, digests,
+ certFingerprint, static_cast<SSLKEAType>(authType), dtlsClient, digests,
privacyRequested);
return ipc::IPCResult::Ok();
}
diff -up firefox-140.0/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp.D225034.1750779491 firefox-140.0/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp
--- firefox-140.0/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/jsapi/PeerConnectionImpl.cpp 2025-06-26 12:14:42.302823315 +0200
@@ -4320,9 +4320,8 @@ void PeerConnectionImpl::UpdateTransport
candidates.end());
}
- nsTArray<uint8_t> keyDer;
- nsTArray<uint8_t> certDer;
- nsresult rv = Identity()->Serialize(&keyDer, &certDer);
+ nsTArray<uint8_t> certFingerprint;
+ nsresult rv = Identity()->Serialize(certFingerprint);
if (NS_FAILED(rv)) {
CSFLogError(LOGTAG, "%s: Failed to serialize DTLS identity: %d",
__FUNCTION__, (int)rv);
@@ -4338,7 +4337,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-140.0/dom/media/webrtc/MediaTransportParent.h.D225034.1750779491 firefox-140.0/dom/media/webrtc/MediaTransportParent.h
--- firefox-140.0/dom/media/webrtc/MediaTransportParent.h.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/MediaTransportParent.h 2025-06-26 12:14:42.303449191 +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<uint8_t>&& keyDer, nsTArray<uint8_t>&& certDer,
- const int& authType, const bool& dtlsClient,
- const DtlsDigestList& digests, const bool& privacyRequested);
+ nsTArray<uint8_t>&& 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-140.0/dom/media/webrtc/moz.build.D225034.1750779491 firefox-140.0/dom/media/webrtc/moz.build
--- firefox-140.0/dom/media/webrtc/moz.build.D225034.1750779491 2025-06-17 18:15:14.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/moz.build 2025-06-26 12:14:42.303672821 +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.
@@ -111,7 +127,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-140.0/dom/media/webrtc/nsIRTCCertService.idl.D225034.1750779491 firefox-140.0/dom/media/webrtc/nsIRTCCertService.idl
--- firefox-140.0/dom/media/webrtc/nsIRTCCertService.idl.D225034.1750779491 2025-06-26 12:14:42.303932017 +0200
+++ firefox-140.0/dom/media/webrtc/nsIRTCCertService.idl 2025-06-26 12:14:42.303932017 +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<mozilla::dom::RTCCertFingerprintPromise>);
+
+native CertData(mozilla::dom::CertData);
+native RTCCertificatePromise(RefPtr<mozilla::dom::RTCCertificatePromise>);
+
+[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<uint8_t> 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-140.0/dom/media/webrtc/PMediaTransport.ipdl.D225034.1750779491 firefox-140.0/dom/media/webrtc/PMediaTransport.ipdl
--- firefox-140.0/dom/media/webrtc/PMediaTransport.ipdl.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/PMediaTransport.ipdl 2025-06-26 12:14:42.304154235 +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-140.0/dom/media/webrtc/PRTCCertServiceTransaction.ipdl.D225034.1750779491 firefox-140.0/dom/media/webrtc/PRTCCertServiceTransaction.ipdl
--- firefox-140.0/dom/media/webrtc/PRTCCertServiceTransaction.ipdl.D225034.1750779491 2025-06-26 12:14:42.304369078 +0200
+++ firefox-140.0/dom/media/webrtc/PRTCCertServiceTransaction.ipdl 2025-06-26 12:14:42.304369078 +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-140.0/dom/media/webrtc/RTCCertCache.cpp.D225034.1750779491 firefox-140.0/dom/media/webrtc/RTCCertCache.cpp
--- firefox-140.0/dom/media/webrtc/RTCCertCache.cpp.D225034.1750779491 2025-06-26 12:14:42.304591095 +0200
+++ firefox-140.0/dom/media/webrtc/RTCCertCache.cpp 2025-06-26 12:14:42.304591095 +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<UniquePtr<GeneratedCertificate>> RTCCertCache::sCertCache;
+mozilla::StaticMutex RTCCertCache::sRTCCertCacheLock MOZ_UNANNOTATED;
+
+void RTCCertCache::CacheCert(UniquePtr<GeneratedCertificate> 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-140.0/dom/media/webrtc/RTCCertCache.h.D225034.1750779491 firefox-140.0/dom/media/webrtc/RTCCertCache.h
--- firefox-140.0/dom/media/webrtc/RTCCertCache.h.D225034.1750779491 2025-06-26 12:14:42.304801480 +0200
+++ firefox-140.0/dom/media/webrtc/RTCCertCache.h 2025-06-26 12:14:42.304801480 +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<GeneratedCertificate> aCert);
+ static GeneratedCertificate* LookupCert(
+ const CertFingerprint aCertFingerprint);
+ static void RemoveCert(const CertFingerprint aCertFingerprint);
+
+ private:
+ static nsTArray<UniquePtr<GeneratedCertificate>> sCertCache;
+ static mozilla::StaticMutex sRTCCertCacheLock MOZ_UNANNOTATED;
+};
+} // namespace mozilla::dom
+
+#endif // mozilla_dom_CertCache_h
diff -up firefox-140.0/dom/media/webrtc/RTCCertificate.cpp.D225034.1750779491 firefox-140.0/dom/media/webrtc/RTCCertificate.cpp
--- firefox-140.0/dom/media/webrtc/RTCCertificate.cpp.D225034.1750779491 2025-06-17 18:15:14.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/RTCCertificate.cpp 2025-06-26 12:38:54.418795430 +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 "sdp/SdpAttribute.h"
@@ -72,196 +72,10 @@ 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<nsString>& 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;
- }
- }
-
- 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);
- }
-
- nsresult GenerateCertificate() {
- UniquePK11SlotInfo slot(PK11_GetInternalSlot());
- MOZ_ASSERT(slot.get());
-
- UniqueCERTName subjectName(GenerateRandomName(slot.get()));
- if (!subjectName) {
- return NS_ERROR_DOM_UNKNOWN_ERR;
- }
-
- UniqueSECKEYPublicKey publicKey(mKeyPair->mPublicKey->GetPublicKey());
- UniqueCERTSubjectPublicKeyInfo spki(
- SECKEY_CreateSubjectPublicKeyInfo(publicKey.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;
- mExpires += now;
-
- UniqueCERTValidity validity(CERT_CreateValidity(notBefore, 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<unsigned char*>(&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;
- }
-
- 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;
- }
-
- mCertificate.reset(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certDer,
- nullptr, false, true));
- if (!mCertificate) {
- return NS_ERROR_DOM_UNKNOWN_ERR;
- }
- return NS_OK;
- }
-
- nsresult BeforeCrypto() override {
- if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
- // Double check that size is OK.
- auto sz = static_cast<size_t>(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 {
- 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;
- }
-
- 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<RTCCertificate> 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.
@@ -288,46 +102,166 @@ static PRTime ReadExpires(JSContext* aCx
return static_cast<PRTime>(expiration.mExpires.Value() * PR_USEC_PER_MSEC);
}
-already_AddRefed<Promise> RTCCertificate::GenerateCertificate(
+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;
+ }
+
+ mArena = UniquePLArenaPool(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+ if (!mArena) {
+ return NS_ERROR_DOM_UNKNOWN_ERR;
+ }
+
+ // Extract algorithm name
+ nsresult rv = GetAlgorithmName(aCx, aAlgorithm, mAlgName);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+
+ // Construct an appropriate KeyAlorithm
+ if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
+ RootedDictionary<RsaHashedKeyGenParams> params(aCx);
+ rv = Coerce(aCx, params, aAlgorithm);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
+
+ // Pull relevant info
+ uint32_t modulusLength = params.mModulusLength;
+ CryptoBuffer publicExponent;
+ if (!publicExponent.Assign(params.mPublicExponent)) {
+
+ 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;
+ }
+
+ mMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
+ // Set up params struct
+ mRsaParams.keySizeInBits = modulusLength;
+ bool converted = publicExponent.GetBigIntValue(mRsaParams.pe);
+ if (!converted) {
+ return NS_ERROR_DOM_INVALID_ACCESS_ERR;
+ }
+
+ auto sz = static_cast<size_t>(mRsaParams.keySizeInBits);
+ if (sz < RTCCertificateMinRsaSize) {
+ return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+ }
+
+ SerializeRSAParam(&mParam, &mRsaParams);
+
+ mSignatureAlg = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
+ *aAuthType = ssl_kea_rsa;
+ } else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_ECDSA)) {
+ RootedDictionary<EcKeyGenParams> params(aCx);
+ rv = Coerce(aCx, params, aAlgorithm);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SYNTAX_ERR);
+ if (!NormalizeToken(params.mNamedCurve, mNamedCurve)) {
+ return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+ }
+ mMechanism = CKM_EC_KEY_PAIR_GEN;
+ if (!SerializeECParams(&mParam,
+ CreateECParamsForCurve(mNamedCurve, mArena.get()))) {
+ return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+ }
+
+ // 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;
+ }
+ return NS_OK;
+}
+
+RefPtr<RTCCertFingerprintPromise> RTCCertificateMetadata::Generate(
+ nsCOMPtr<nsIRTCCertService> aCertService) {
+ return aCertService->GenerateCertificate(mParam, mExpires, mMechanism,
+ mSignatureAlg);
+}
+
+already_AddRefed<Promise> RTCCertificate::Generate(
const GlobalObject& aGlobal, const ObjectOrString& aOptions,
- ErrorResult& aRv, JS::Compartment* aCompartment) {
+ ErrorResult& aRv) {
nsIGlobalObject* global = xpc::NativeGlobal(aGlobal.Get());
- RefPtr<Promise> p = Promise::Create(global, aRv);
+ RefPtr<Promise> resultPromise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
- Sequence<nsString> 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<WebCryptoTask> 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<CertData>&& 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<Promise> RTCCertificate::GenerateCertificate(
+ const GlobalObject& aGlobal, const ObjectOrString& aOptions,
+ ErrorResult& aRv, JS::Compartment* aCompartment) {
+ RefPtr<RTCCertificate> 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);
+ }
+ */
+}
void RTCCertificate::GetFingerprints(
nsTArray<dom::RTCDtlsFingerprint>& aFingerprintsOut) {
@@ -357,13 +291,10 @@ void RTCCertificate::GetFingerprints(
}
RefPtr<DtlsIdentity> RTCCertificate::CreateDtlsIdentity() const {
- if (!mPrivateKey || !mCertificate) {
+ if (!mCertificate) {
return nullptr;
}
- UniqueSECKEYPrivateKey key(SECKEY_CopyPrivateKey(mPrivateKey.get()));
- UniqueCERTCertificate cert(CERT_DupCertificate(mCertificate.get()));
- RefPtr<DtlsIdentity> id =
- new DtlsIdentity(std::move(key), std::move(cert), mAuthType);
+ RefPtr<DtlsIdentity> id = new DtlsIdentity(mCertFingerprint, mAuthType);
return id;
}
@@ -372,17 +303,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 {
@@ -398,27 +322,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) {
@@ -456,7 +376,8 @@ already_AddRefed<RTCCertificate> RTCCert
}
cert->mExpires = static_cast<PRTime>(high) << 32 | low;
- if (!cert->ReadPrivateKey(aReader) || !cert->ReadCertificate(aReader)) {
+ if (!cert->ReadCertificateFingerprint(aReader) ||
+ !cert->ReadCertificate(aReader)) {
return nullptr;
}
diff -up firefox-140.0/dom/media/webrtc/RTCCertificate.h.D225034.1750779491 firefox-140.0/dom/media/webrtc/RTCCertificate.h
--- firefox-140.0/dom/media/webrtc/RTCCertificate.h.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/RTCCertificate.h 2025-06-26 12:42:14.067026422 +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"
@@ -40,6 +44,27 @@ namespace dom {
class GlobalObject;
class ObjectOrString;
class Promise;
+
+class RTCCertificateMetadata {
+ public:
+ RTCCertificateMetadata();
+
+ nsresult Init(JSContext* aCx, const ObjectOrString& aAlgorithm,
+ SSLKEAType* aAuthType, ErrorResult& aRv);
+ RefPtr<RTCCertFingerprintPromise> Generate(
+ nsCOMPtr<nsIRTCCertService> aCertService);
+
+ private:
+ nsTArray<uint8_t> mParam;
+ PRTime mExpires;
+ SECOidTag mSignatureAlg;
+ UniquePLArenaPool mArena;
+ CK_MECHANISM_TYPE mMechanism;
+ PK11RSAGenParams mRsaParams;
+ nsString mNamedCurve;
+ nsString mAlgName;
+};
+
struct RTCDtlsFingerprint;
class RTCCertificate final : public nsISupports, public nsWrapperCache {
@@ -53,9 +78,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,
@@ -78,21 +100,30 @@ 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<Promise> 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<nsIGlobalObject> mGlobal;
- UniqueSECKEYPrivateKey mPrivateKey;
+ CertFingerprint mCertFingerprint;
+
+ RTCCertificateMetadata mData;
+
+ nsCOMPtr<nsIRTCCertService> mCertService;
UniqueCERTCertificate mCertificate;
- SSLKEAType mAuthType;
- PRTime mExpires;
nsTArray<RTCDtlsFingerprint> mFingerprints;
+ SSLKEAType mAuthType = ssl_kea_null;
+ PRTime mExpires = 0;
};
} // namespace dom
diff -up firefox-140.0/dom/media/webrtc/RTCCertService.cpp.D225034.1750779491 firefox-140.0/dom/media/webrtc/RTCCertService.cpp
--- firefox-140.0/dom/media/webrtc/RTCCertService.cpp.D225034.1750779491 2025-06-26 12:14:42.306004069 +0200
+++ firefox-140.0/dom/media/webrtc/RTCCertService.cpp 2025-06-26 12:14:42.306004069 +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<nsIRTCCertService> NewRTCCertService() {
+ nsCOMPtr<nsIRTCCertService> certService(new RTCCertService());
+ certService->Initialize();
+ return certService.forget();
+}
+
+void RTCCertService::Initialize() {
+ using EndpointPromise =
+ MozPromise<mozilla::ipc::Endpoint<PRTCCertServiceTransactionChild>,
+ nsCString, true>;
+ mInitPromise =
+ net::SocketProcessBridgeChild::GetSocketProcessBridge()
+ ->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [](const RefPtr<net::SocketProcessBridgeChild>& aBridge) {
+ mozilla::ipc::Endpoint<PRTCCertServiceTransactionParent>
+ parentEndpoint;
+ mozilla::ipc::Endpoint<PRTCCertServiceTransactionChild>
+ 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<RTCCertService>(this)](
+ mozilla::ipc::Endpoint<PRTCCertServiceTransactionChild>&&
+ aEndpoint) {
+ RefPtr<RTCCertServiceTransactionChild> 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<RTCCertFingerprintPromise> RTCCertService::GenerateCertificate(
+ const nsTArray<uint8_t>& aParam, PRTime aExpires, uint32_t aMechanism,
+ uint32_t aSignatureAlg) {
+ return mInitPromise->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [self = RefPtr<RTCCertService>(this), this, param = aParam.Clone(),
+ aExpires, aMechanism, aSignatureAlg](bool /* dummy */) {
+ if (!mChild) {
+ return RTCCertFingerprintPromise::CreateAndReject(NS_ERROR_FAILURE,
+ __func__);
+ }
+ RefPtr<RTCCertFingerprintPromise> 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<RTCCertService>(this), this,
+ aCertFingerprint](bool /* dummy */) {
+ if (mChild) {
+ mChild->SendRemoveCertificate(aCertFingerprint);
+ }
+ },
+ [](const nsCString& aError) {});
+}
+
+RefPtr<RTCCertificatePromise> RTCCertService::GetCertificate(
+ const CertFingerprint aCertFingerprint) {
+ return mInitPromise->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [self = RefPtr<RTCCertService>(this), this,
+ aCertFingerprint](bool /* dummy */) {
+ if (!mChild) {
+ return RTCCertificatePromise::CreateAndReject(NS_ERROR_FAILURE,
+ __func__);
+ }
+ RefPtr<RTCCertificatePromise> promise =
+ mChild->SendGetCertificate(aCertFingerprint)
+ ->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [](const CertDataIPC& aCertDataIPC) {
+ return RTCCertificatePromise::CreateAndResolve(
+ MakeUnique<CertData>(&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-140.0/dom/media/webrtc/RTCCertServiceData.cpp.D225034.1750779491 firefox-140.0/dom/media/webrtc/RTCCertServiceData.cpp
--- firefox-140.0/dom/media/webrtc/RTCCertServiceData.cpp.D225034.1750779491 2025-06-26 12:14:42.306223801 +0200
+++ firefox-140.0/dom/media/webrtc/RTCCertServiceData.cpp 2025-06-26 12:14:42.306223801 +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<uint8_t>& aCertFingerprint) {
+ MOZ_ASSERT(aCertFingerprint.Length() == sHashByteLen);
+ memcpy(mHash, const_cast<uint8_t*>(aCertFingerprint.Elements()),
+ static_cast<unsigned int>(aCertFingerprint.Length()));
+}
+
+CertFingerprint::operator nsTArray<uint8_t>() {
+ nsTArray<uint8_t> ret;
+ ret.AppendElements(reinterpret_cast<unsigned char*>(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<uint8_t*>(aCertDataIPC->mCertificate.Elements()),
+ static_cast<unsigned int>(aCertDataIPC->mCertificate.Length())};
+ UniqueCERTCertificate cert(CERT_NewTempCertificate(
+ CERT_GetDefaultCertDB(), &certDer, nullptr, true, true));
+ mCertificate = std::move(cert);
+ mExpires = aCertDataIPC->mExpires;
+}
+
+void SerializeRSAParam(nsTArray<uint8_t>* aParams,
+ PK11RSAGenParams* aRsaParams) {
+ aParams->AppendElements(reinterpret_cast<uint8_t*>(aRsaParams),
+ sizeof(*aRsaParams));
+}
+
+PK11RSAGenParams DeserializeRSAParam(nsTArray<uint8_t>* aParams) {
+ MOZ_ASSERT(aParams->Length() <= sizeof(PK11RSAGenParams));
+ return *(reinterpret_cast<PK11RSAGenParams*>(aParams->Elements()));
+}
+
+bool SerializeECParams(nsTArray<uint8_t>* aParams, SECItem* aECParams) {
+ if (!aECParams) {
+ return false;
+ }
+ aParams->AppendElements(reinterpret_cast<uint8_t*>(aECParams->data),
+ aECParams->len);
+ return true;
+}
+
+SECItem* DeserializeECParams(nsTArray<uint8_t>* aParams) {
+ SECItem* ret = ::SECITEM_AllocItem(nullptr, nullptr, 0);
+ SECItem it = {siBuffer, reinterpret_cast<uint8_t*>(aParams->Elements()),
+ static_cast<unsigned int>(aParams->Length())};
+ if (::SECITEM_CopyItem(nullptr, ret, &it) != SECSuccess) {
+ return nullptr;
+ }
+ return ret;
+}
+
+} // namespace mozilla::dom
diff -up firefox-140.0/dom/media/webrtc/RTCCertServiceData.h.D225034.1750779491 firefox-140.0/dom/media/webrtc/RTCCertServiceData.h
--- firefox-140.0/dom/media/webrtc/RTCCertServiceData.h.D225034.1750779491 2025-06-26 12:14:42.306399401 +0200
+++ firefox-140.0/dom/media/webrtc/RTCCertServiceData.h 2025-06-26 12:14:42.306399401 +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<uint8_t>& aCertFingerprint);
+ operator nsTArray<uint8_t>();
+
+ bool Match(const struct CertFingerprint* aCertFingerprint);
+ unsigned char* AsChar() { return reinterpret_cast<unsigned char*>(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<uint8_t> 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<CertFingerprint, nsresult, /* IsExclusive = */ true>;
+using RTCCertificatePromise =
+ MozPromise<UniquePtr<CertData>, nsresult, /* IsExclusive = */ true>;
+
+void SerializeRSAParam(nsTArray<uint8_t>* aParams,
+ PK11RSAGenParams* aRsaParams);
+PK11RSAGenParams DeserializeRSAParam(nsTArray<uint8_t>* aParams);
+
+bool SerializeECParams(nsTArray<uint8_t>* aParams, SECItem* aECParams);
+SECItem* DeserializeECParams(nsTArray<uint8_t>* aParams);
+} // namespace dom
+
+namespace ipc {
+template <>
+struct IPDLParamTraits<dom::CertFingerprint> {
+ 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<dom::CertDataIPC> {
+ 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-140.0/dom/media/webrtc/RTCCertService.h.D225034.1750779491 firefox-140.0/dom/media/webrtc/RTCCertService.h
--- firefox-140.0/dom/media/webrtc/RTCCertService.h.D225034.1750779491 2025-06-26 12:14:42.306588336 +0200
+++ firefox-140.0/dom/media/webrtc/RTCCertService.h 2025-06-26 12:14:42.306588336 +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<nsIRTCCertService> 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<RTCCertServiceTransactionChild> 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<bool, nsCString, false> InitPromise;
+ RefPtr<InitPromise> mInitPromise;
+};
+
+} // namespace mozilla::dom
+
+#endif // mozilla_dom_CertServiceChild_h
diff -up firefox-140.0/dom/media/webrtc/RTCCertServiceParent.cpp.D225034.1750779491 firefox-140.0/dom/media/webrtc/RTCCertServiceParent.cpp
--- firefox-140.0/dom/media/webrtc/RTCCertServiceParent.cpp.D225034.1750779491 2025-06-26 12:14:42.306799462 +0200
+++ firefox-140.0/dom/media/webrtc/RTCCertServiceParent.cpp 2025-06-26 12:14:42.306799462 +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<UniquePtr<GeneratedCertificate>, nsresult,
+ /* IsExclusive = */ true>;
+
+class RTCCertificateGenerator final : public CancelableRunnable {
+ public:
+ RTCCertificateGenerator();
+ RefPtr<RTCCertificateGeneratorPromise> Generate(nsTArray<uint8_t>& 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<GeneratedCertificate> 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<RTCCertificateGeneratorPromise::Private> mGenPromise;
+ nsCOMPtr<nsISerialEventTarget> 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<unsigned char*>(&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<int32_t>(certDer->len)) != SECSuccess) {
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+RefPtr<RTCCertificateGeneratorPromise> RTCCertificateGenerator::Generate(
+ nsTArray<uint8_t>& aParam, PRTime aExpires, CK_MECHANISM_TYPE aMechanism,
+ SECOidTag aSignatureAlg) {
+ mGenPromise = MakeRefPtr<RTCCertificateGeneratorPromise::Private>(__func__);
+
+ mGen = MakeUnique<GeneratedCertificate>();
+ 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<RTCCertFingerprintPromise> RTCCertServiceParent::GenerateCertificate(
+ nsTArray<uint8_t>& aParam, PRTime aExpires, uint32_t aMechanism,
+ uint32_t aSignatureAlg) {
+ RefPtr<RTCCertFingerprintPromise::Private> resultPromise =
+ MakeRefPtr<RTCCertFingerprintPromise::Private>(__func__);
+
+ RefPtr<RTCCertificateGenerator> gen = new RTCCertificateGenerator();
+ gen->Generate(aParam, aExpires, aMechanism,
+ static_cast<SECOidTag>(aSignatureAlg))
+ ->Then(GetCurrentSerialEventTarget(), __func__,
+ [s = RefPtr{this}, resultPromise](
+ RTCCertificateGeneratorPromise::ResolveOrRejectValue&&
+ aValue) mutable {
+ if (aValue.IsResolve()) {
+ UniquePtr<GeneratedCertificate> 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<RTCCertificatePromise> RTCCertServiceParent::GetCertificate(
+ const CertFingerprint aCertFingerprint) {
+ if (GeneratedCertificate* cert = RTCCertCache::LookupCert(aCertFingerprint)) {
+ auto data = MakeUnique<CertData>(
+ 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<uint8_t>&& 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-140.0/dom/media/webrtc/RTCCertServiceParent.h.D225034.1750779491 firefox-140.0/dom/media/webrtc/RTCCertServiceParent.h
--- firefox-140.0/dom/media/webrtc/RTCCertServiceParent.h.D225034.1750779491 2025-06-26 12:14:42.307072966 +0200
+++ firefox-140.0/dom/media/webrtc/RTCCertServiceParent.h 2025-06-26 12:14:42.307072966 +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<uint8_t>&& 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<RTCCertFingerprintPromise> GenerateCertificate(
+ nsTArray<uint8_t>& aParam, PRTime aExpires, uint32_t aMechanism,
+ uint32_t aSignatureAlg);
+ RefPtr<RTCCertificatePromise> GetCertificate(
+ const CertFingerprint aCertFingerprint);
+
+ private:
+ ~RTCCertServiceParent() = default;
+};
+
+} // namespace mozilla::dom
+
+#endif // mozilla_dom_CertServiceTransactionParent_h
diff -up firefox-140.0/dom/media/webrtc/transport/dtlsidentity.cpp.D225034.1750779491 firefox-140.0/dom/media/webrtc/transport/dtlsidentity.cpp
--- firefox-140.0/dom/media/webrtc/transport/dtlsidentity.cpp.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/transport/dtlsidentity.cpp 2025-06-26 12:14:42.307331702 +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<uint8_t>* aKeyDer,
- nsTArray<uint8_t>* 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<uint8_t>& certFingerprint) {
+ certFingerprint = cert_fingerprint_;
return NS_OK;
}
/* static */
RefPtr<DtlsIdentity> DtlsIdentity::Deserialize(
- const nsTArray<uint8_t>& aKeyDer, const nsTArray<uint8_t>& aCertDer,
- SSLKEAType authType) {
- SECItem certDer = {siBuffer, const_cast<uint8_t*>(aCertDer.Elements()),
- static_cast<unsigned int>(aCertDer.Length())};
- UniqueCERTCertificate cert(CERT_NewTempCertificate(
- CERT_GetDefaultCertDB(), &certDer, nullptr, true, true));
-
- SECItem derPKI = {siBuffer, const_cast<uint8_t*>(aKeyDer.Elements()),
- static_cast<unsigned int>(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<uint8_t>& certFingerprint, SSLKEAType authType) {
+ return new DtlsIdentity(dom::CertFingerprint(certFingerprint), authType);
}
RefPtr<DtlsIdentity> DtlsIdentity::Generate() {
@@ -283,7 +166,7 @@ RefPtr<DtlsIdentity> 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-140.0/dom/media/webrtc/transport/dtlsidentity.h.D225034.1750779491 firefox-140.0/dom/media/webrtc/transport/dtlsidentity.h
--- firefox-140.0/dom/media/webrtc/transport/dtlsidentity.h.D225034.1750779491 2025-06-17 18:15:13.000000000 +0200
+++ firefox-140.0/dom/media/webrtc/transport/dtlsidentity.h 2025-06-26 12:14:42.307559680 +0200
@@ -10,6 +10,7 @@
#include <vector>
#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<uint8_t>* aKeyDer, nsTArray<uint8_t>* aCertDer);
- static RefPtr<DtlsIdentity> Deserialize(const nsTArray<uint8_t>& aKeyDer,
- const nsTArray<uint8_t>& aCertDer,
- SSLKEAType authType);
+ nsresult Serialize(nsTArray<uint8_t>& certFingerprint);
+ static RefPtr<DtlsIdentity> Deserialize(
+ const nsTArray<uint8_t>& 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-140.0/ipc/glue/BackgroundParentImpl.cpp.D225034.1750779491 firefox-140.0/ipc/glue/BackgroundParentImpl.cpp
--- firefox-140.0/ipc/glue/BackgroundParentImpl.cpp.D225034.1750779491 2025-06-17 18:15:14.000000000 +0200
+++ firefox-140.0/ipc/glue/BackgroundParentImpl.cpp 2025-06-26 12:14:42.307823345 +0200
@@ -59,6 +59,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-140.0/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp.D225034.1750779491 firefox-140.0/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
--- firefox-140.0/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp.D225034.1750779491 2025-06-17 18:15:19.000000000 +0200
+++ firefox-140.0/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp 2025-06-26 12:14:42.308182079 +0200
@@ -200,13 +200,15 @@ class LoopbackTransport : public MediaTr
// this up internally
const nsTArray<NrIceStunAddr>& 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<uint8_t>& aKeyDer, const nsTArray<uint8_t>& 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<uint8_t>& aCertFingerprint,
+ SSLKEAType aAuthType, bool aDtlsClient,
+ const DtlsDigestList& aDigests,
+ bool aPrivacyRequested) override {}
void RemoveTransportsExcept(
const std::set<std::string>& aTransportIds) override {}
diff -up firefox-140.0/netwerk/ipc/PSocketProcessBridge.ipdl.D225034.1750779491 firefox-140.0/netwerk/ipc/PSocketProcessBridge.ipdl
--- firefox-140.0/netwerk/ipc/PSocketProcessBridge.ipdl.D225034.1750779491 2025-06-17 18:15:20.000000000 +0200
+++ firefox-140.0/netwerk/ipc/PSocketProcessBridge.ipdl 2025-06-26 12:14:42.308456975 +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<PMediaTransportParent> aEndpoint);
#endif // MOZ_WEBRTC
+ async InitRTCCertServiceTransaction(Endpoint<PRTCCertServiceTransactionParent> aEndpoint);
};
}
diff -up firefox-140.0/netwerk/ipc/SocketProcessBridgeParent.cpp.D225034.1750779491 firefox-140.0/netwerk/ipc/SocketProcessBridgeParent.cpp
--- firefox-140.0/netwerk/ipc/SocketProcessBridgeParent.cpp.D225034.1750779491 2025-06-17 18:15:20.000000000 +0200
+++ firefox-140.0/netwerk/ipc/SocketProcessBridgeParent.cpp 2025-06-26 12:14:42.308665677 +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<mozilla::dom::PRTCCertServiceTransactionParent>&&
+ aEndpoint) {
+ LOG(("SocketProcessBridgeParent::RecvInitRTCCertServiceTransaction\n"));
+
+ if (!aEndpoint.IsValid()) {
+ return IPC_FAIL(this, "Invalid endpoint");
+ }
+
+ if (!mMediaTransportTaskQueue) {
+ nsCOMPtr<nsISerialEventTarget> 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<dom::RTCCertServiceParent> 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-140.0/netwerk/ipc/SocketProcessBridgeParent.h.D225034.1750779491 firefox-140.0/netwerk/ipc/SocketProcessBridgeParent.h
--- firefox-140.0/netwerk/ipc/SocketProcessBridgeParent.h.D225034.1750779491 2025-06-17 18:15:20.000000000 +0200
+++ firefox-140.0/netwerk/ipc/SocketProcessBridgeParent.h 2025-06-26 12:14:42.308878987 +0200
@@ -29,6 +29,9 @@ class SocketProcessBridgeParent final :
Endpoint<PMediaTransportParent>&& aEndpoint);
#endif
+ mozilla::ipc::IPCResult RecvInitRTCCertServiceTransaction(
+ Endpoint<PRTCCertServiceTransactionParent>&& aEndpoint);
+
void ActorDestroy(ActorDestroyReason aReason) override;
private: