From ee63e85695bba2d9ae705c458d2e14a80c5d166e Mon Sep 17 00:00:00 2001 From: Hamish Willee Date: Mon, 22 Jun 2026 18:34:54 +1000 Subject: [PATCH 1/7] FF153 RTCDtlsTransport: getRemoteCertificates() --- .../getremotecertificates/index.md | 126 ++++++++++++++++++ files/en-us/web/api/rtcdtlstransport/index.md | 5 +- 2 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md diff --git a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md new file mode 100644 index 000000000000000..7556527464cbecf --- /dev/null +++ b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md @@ -0,0 +1,126 @@ +--- +title: "RTCDtlsTransport: getRemoteCertificates() method" +short-title: getRemoteCertificates() +slug: Web/API/RTCDtlsTransport/getRemoteCertificates +page-type: web-api-instance-method +browser-compat: api.RTCDtlsTransport.getRemoteCertificates +--- + +{{APIRef("WebRTC")}} + +The **`getRemoteCertificates()`** method of the {{domxref("RTCDtlsTransport")}} interface is used to get the certificates from the remote peer of the connection. + +## Syntax + +```js-nolint +getRemoteCertificates() +``` + +### Parameters + +None. + +### Return value + +An {{jsxref("ArrayBuffer")}} containing the public certificates of the remote peer of the connection. + +For [`new`](/en-US/docs/Web/API/RTCDtlsTransport/state#new) connections this is an empty array. +It is populated with the certificates from the remote peer when the state of the transport changes to [`connected`](/en-US/docs/Web/API/RTCDtlsTransport/state#connected). + +### Exceptions + +None + +## Description + +WebRTC media and data channels are secured using DTLS (Datagram Transport Layer Security). +The protocol automatically uses certificates to ensure that the communicating remote peer is the same entity that negotiated the connection via the signaling server. +This is done by checking that the certificate presented during the DTLS handshake matches the `a=fingerprint` provided in the SDP. + +DTLS guarantees the connected peer is the one you've been negotiating with, because only that peer has the private key matching the certificate whose fingerprint was exchanged during signaling. +However it doesn't tell you who this remote peer is: DTLS can't help you if you initially connected to a compromised signaling server, or some unexpected peer. +Establishing the identity of the remote peer usually requires an out-of-band mechanism such as comparing certificate fingerprints verbally over a phone call, or using a separate authenticated channel. + +The `getRemoteCertificates()` method allows you to get the remote certificates used by DTLS and use them for _application-layer_ authentication of the remote peer. + +The way this works is that each peer must persist their own DTLS certificate across sessions, rather than generating a new one each time. +After connecting to the remote peer, you'd exchange information out-of-band to verify that it is the intended party, and use `getRemoteCertificates()` to get its certificates. +When you subsequently connect to that remote peer you'd only allow communication if it has exactly the same certificate fingerprints. +There is still a window for a person-in-the-middle attack, but it only exists for the very first connection between peers. + +Note that `getRemoteCertificates()` returns an `ArrayBuffer`, which unlike {{domxref("RTCCertificate")}} does not provide direct access to fingerprint information. +Applications that need to compare fingerprints must parse the raw DER-encoded certificate data themselves, for example by hashing it with SHA-256. + +## Example + +### Basic usage + +This function shows how you might get and fingerprint the remote peer's certificate after the DTLS handshake, and compare it to a stored value. + +```js +async function getRemoteFingerprint(pc) { + const certs = pc.getRemoteCertificates(); + if (certs.length === 0) { + return null; + } + + // Hash the raw DER-encoded certificate with SHA-256 + const digest = await crypto.subtle.digest("SHA-256", certs[0]); + + // Format as colon-separated hex, matching the SDP a=fingerprint convention + return Array.from(new Uint8Array(digest)) + .map((b) => b.toString(16).padStart(2, "0")) + .join(":"); +} + +// Call once DTLS handshake is complete +pc.oniceconnectionstatechange = async () => { + if (pc.iceConnectionState === "connected") { + const fingerprint = await getRemoteFingerprint(pc); + const stored = localStorage.getItem("remote-peer-id"); + + if (!stored) { + localStorage.setItem("remote-peer-id", fingerprint); + } else if (stored !== fingerprint) { + console.error("Certificate mismatch — closing connection"); + pc.close(); + } + } +}; +``` + +This code shows how you might persist your DTLS certificate across sessions. +It is needed because by default DTLS will generate a fresh certificate each time. + +```js +// Persist your own +async function getOrCreateCertificate() { + const stored = localStorage.getItem("dtls-cert"); + if (stored) { + return JSON.parse(stored); + } + const cert = await RTCPeerConnection.generateCertificate({ + name: "ECDSA", + namedCurve: "P-256", + }); + localStorage.setItem("dtls-cert", JSON.stringify(cert)); + return cert; +} + +const pc = new RTCPeerConnection({ + certificates: [await getOrCreateCertificate()], +}); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [WebRTC API](/en-US/docs/Web/API/WebRTC_API) +- [Introduction to the Real-time Transport Protocol (RTP)](/en-US/docs/Web/API/WebRTC_API/Intro_to_RTP) diff --git a/files/en-us/web/api/rtcdtlstransport/index.md b/files/en-us/web/api/rtcdtlstransport/index.md index 293f5c27424f4ab..f4f0dd6f8fddac3 100644 --- a/files/en-us/web/api/rtcdtlstransport/index.md +++ b/files/en-us/web/api/rtcdtlstransport/index.md @@ -32,7 +32,7 @@ _Also inherits properties from {{DOMxRef("EventTarget")}}._ _Also inherits methods from {{DOMxRef("EventTarget")}}._ - {{DOMxRef("RTCDtlsTransport.getRemoteCertificates", "getRemoteCertificates()")}} - - : Returns an array of {{jsxref("ArrayBuffer")}} containing the certificates of the remote peer of the connection. + - : Returns an {{jsxref("ArrayBuffer")}} containing the certificates of the remote peer of the connection. ## Events @@ -48,6 +48,7 @@ _Also inherits methods from {{DOMxRef("EventTarget")}}._ `RTCDtlsTransport` objects are created when an app calls either {{domxref("RTCPeerConnection.setLocalDescription", "setLocalDescription()")}} or {{domxref("RTCPeerConnection.setRemoteDescription", "setRemoteDescription()")}}. The number of DTLS transports created and how they're used depends on the bundling mode used when creating the {{domxref("RTCPeerConnection")}}. +[Bundling](https://datatracker.ietf.org/doc/rfc8843/) lets you use one `RTCDtlsTransport` to carry the data for multiple higher-level transports, such as multiple {{domxref("RTCRtpTransceiver")}}s. Whether bundling is used depends on what the other endpoint is able to negotiate. All browsers support bundling, so when both endpoints are browsers, you can rest assured that bundling will be used. Some non-browser legacy endpoints, however, may not support bundle. To be able to negotiate with such endpoints (or to exclude them entirely), the `bundlePolicy` property may be provided when creating the connection. The `bundlePolicy` lets you control how to negotiate with these legacy endpoints. The default policy is `"balanced"`, which provides a balance between performance and compatibility. @@ -62,8 +63,6 @@ const rtcConfig = { const pc = new RTCPeerConnection(rtcConfig); ``` -[Bundling](https://datatracker.ietf.org/doc/rfc8843/) lets you use one `RTCDtlsTransport` to carry the data for multiple higher-level transports, such as multiple {{domxref("RTCRtpTransceiver")}}s. - #### When not using BUNDLE When the connection is created without using BUNDLE, each RTP or RTCP component of each {{domxref("RTCRtpTransceiver")}} has its own `RTCDtlsTransport`; that is, every {{domxref("RTCRtpSender")}} and {{domxref("RTCRtpReceiver")}}, has its own transport, and all {{domxref("RTCDataChannel")}} objects share a transport dedicated to SCTP. From 422c5891a31e765d65964e9cdd24f7a878dcfd72 Mon Sep 17 00:00:00 2001 From: Hamish Willee Date: Mon, 22 Jun 2026 18:52:31 +1000 Subject: [PATCH 2/7] Fixes to return value --- .../getremotecertificates/index.md | 48 ++++++------------- files/en-us/web/api/rtcdtlstransport/index.md | 2 +- 2 files changed, 15 insertions(+), 35 deletions(-) diff --git a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md index 7556527464cbecf..a640eed52001370 100644 --- a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md +++ b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md @@ -22,7 +22,7 @@ None. ### Return value -An {{jsxref("ArrayBuffer")}} containing the public certificates of the remote peer of the connection. +An array of {{jsxref("ArrayBuffer")}} objects containing the public certificates of the remote peer of the connection. For [`new`](/en-US/docs/Web/API/RTCDtlsTransport/state#new) connections this is an empty array. It is populated with the certificates from the remote peer when the state of the transport changes to [`connected`](/en-US/docs/Web/API/RTCDtlsTransport/state#connected). @@ -38,17 +38,17 @@ The protocol automatically uses certificates to ensure that the communicating re This is done by checking that the certificate presented during the DTLS handshake matches the `a=fingerprint` provided in the SDP. DTLS guarantees the connected peer is the one you've been negotiating with, because only that peer has the private key matching the certificate whose fingerprint was exchanged during signaling. -However it doesn't tell you who this remote peer is: DTLS can't help you if you initially connected to a compromised signaling server, or some unexpected peer. +However, it doesn't tell you who this remote peer is: DTLS can't help you if you initially connected to a compromised signaling server, or some unexpected peer. Establishing the identity of the remote peer usually requires an out-of-band mechanism such as comparing certificate fingerprints verbally over a phone call, or using a separate authenticated channel. The `getRemoteCertificates()` method allows you to get the remote certificates used by DTLS and use them for _application-layer_ authentication of the remote peer. The way this works is that each peer must persist their own DTLS certificate across sessions, rather than generating a new one each time. After connecting to the remote peer, you'd exchange information out-of-band to verify that it is the intended party, and use `getRemoteCertificates()` to get its certificates. -When you subsequently connect to that remote peer you'd only allow communication if it has exactly the same certificate fingerprints. +When you subsequently connect to that remote peer, you'd only allow communication if it has exactly the same certificate fingerprints. There is still a window for a person-in-the-middle attack, but it only exists for the very first connection between peers. -Note that `getRemoteCertificates()` returns an `ArrayBuffer`, which unlike {{domxref("RTCCertificate")}} does not provide direct access to fingerprint information. +Note that `getRemoteCertificates()` returns `ArrayBuffer` objects, which unlike {{domxref("RTCCertificate")}} do not provide direct access to fingerprint information. Applications that need to compare fingerprints must parse the raw DER-encoded certificate data themselves, for example by hashing it with SHA-256. ## Example @@ -58,8 +58,8 @@ Applications that need to compare fingerprints must parse the raw DER-encoded ce This function shows how you might get and fingerprint the remote peer's certificate after the DTLS handshake, and compare it to a stored value. ```js -async function getRemoteFingerprint(pc) { - const certs = pc.getRemoteCertificates(); +async function getRemoteFingerprint(dtlsTransport) { + const certs = dtlsTransport.getRemoteCertificates(); if (certs.length === 0) { return null; } @@ -74,41 +74,21 @@ async function getRemoteFingerprint(pc) { } // Call once DTLS handshake is complete -pc.oniceconnectionstatechange = async () => { - if (pc.iceConnectionState === "connected") { - const fingerprint = await getRemoteFingerprint(pc); - const stored = localStorage.getItem("remote-peer-id"); +pc.addEventListener("connectionstatechange", async () => { + if (pc.connectionState === "connected") { + const sender = pc.getSenders()[0]; + if (!sender?.transport) return; + + const fingerprint = await getRemoteFingerprint(sender.transport); + const stored = localStorage.getItem("remote-peer-fingerprint"); if (!stored) { - localStorage.setItem("remote-peer-id", fingerprint); + localStorage.setItem("remote-peer-fingerprint", fingerprint); } else if (stored !== fingerprint) { console.error("Certificate mismatch — closing connection"); pc.close(); } } -}; -``` - -This code shows how you might persist your DTLS certificate across sessions. -It is needed because by default DTLS will generate a fresh certificate each time. - -```js -// Persist your own -async function getOrCreateCertificate() { - const stored = localStorage.getItem("dtls-cert"); - if (stored) { - return JSON.parse(stored); - } - const cert = await RTCPeerConnection.generateCertificate({ - name: "ECDSA", - namedCurve: "P-256", - }); - localStorage.setItem("dtls-cert", JSON.stringify(cert)); - return cert; -} - -const pc = new RTCPeerConnection({ - certificates: [await getOrCreateCertificate()], }); ``` diff --git a/files/en-us/web/api/rtcdtlstransport/index.md b/files/en-us/web/api/rtcdtlstransport/index.md index f4f0dd6f8fddac3..277d577bea0f8eb 100644 --- a/files/en-us/web/api/rtcdtlstransport/index.md +++ b/files/en-us/web/api/rtcdtlstransport/index.md @@ -32,7 +32,7 @@ _Also inherits properties from {{DOMxRef("EventTarget")}}._ _Also inherits methods from {{DOMxRef("EventTarget")}}._ - {{DOMxRef("RTCDtlsTransport.getRemoteCertificates", "getRemoteCertificates()")}} - - : Returns an {{jsxref("ArrayBuffer")}} containing the certificates of the remote peer of the connection. + - : Returns an array of {{jsxref("ArrayBuffer")}} objects containing the certificates of the remote peer of the connection. ## Events From 8e175d656801fbbfc7346fcc0b68aeab0c531fb0 Mon Sep 17 00:00:00 2001 From: Hamish Willee Date: Tue, 23 Jun 2026 14:41:44 +1000 Subject: [PATCH 3/7] Add info about the data in returned ArrayBuffers --- .../getremotecertificates/index.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md index a640eed52001370..90be8fc66437518 100644 --- a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md +++ b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md @@ -8,7 +8,7 @@ browser-compat: api.RTCDtlsTransport.getRemoteCertificates {{APIRef("WebRTC")}} -The **`getRemoteCertificates()`** method of the {{domxref("RTCDtlsTransport")}} interface is used to get the certificates from the remote peer of the connection. +The **`getRemoteCertificates()`** method of the {{domxref("RTCDtlsTransport")}} interface returns the certificates of the remote peer of the DTLS connection. ## Syntax @@ -22,9 +22,9 @@ None. ### Return value -An array of {{jsxref("ArrayBuffer")}} objects containing the public certificates of the remote peer of the connection. +An array of {{jsxref("ArrayBuffer")}} objects, each containing a DER-encoded X.509 certificate of the remote peer. -For [`new`](/en-US/docs/Web/API/RTCDtlsTransport/state#new) connections this is an empty array. +For [`new`](/en-US/docs/Web/API/RTCDtlsTransport/state#new) connections, this is an empty array. It is populated with the certificates from the remote peer when the state of the transport changes to [`connected`](/en-US/docs/Web/API/RTCDtlsTransport/state#connected). ### Exceptions @@ -38,7 +38,7 @@ The protocol automatically uses certificates to ensure that the communicating re This is done by checking that the certificate presented during the DTLS handshake matches the `a=fingerprint` provided in the SDP. DTLS guarantees the connected peer is the one you've been negotiating with, because only that peer has the private key matching the certificate whose fingerprint was exchanged during signaling. -However, it doesn't tell you who this remote peer is: DTLS can't help you if you initially connected to a compromised signaling server, or some unexpected peer. +However, it doesn't tell you who this remote peer is: DTLS can't help you if you initially connected to a compromised signaling server, or to some unexpected peer. Establishing the identity of the remote peer usually requires an out-of-band mechanism such as comparing certificate fingerprints verbally over a phone call, or using a separate authenticated channel. The `getRemoteCertificates()` method allows you to get the remote certificates used by DTLS and use them for _application-layer_ authentication of the remote peer. @@ -48,14 +48,13 @@ After connecting to the remote peer, you'd exchange information out-of-band to v When you subsequently connect to that remote peer, you'd only allow communication if it has exactly the same certificate fingerprints. There is still a window for a person-in-the-middle attack, but it only exists for the very first connection between peers. -Note that `getRemoteCertificates()` returns `ArrayBuffer` objects, which unlike {{domxref("RTCCertificate")}} do not provide direct access to fingerprint information. -Applications that need to compare fingerprints must parse the raw DER-encoded certificate data themselves, for example by hashing it with SHA-256. +Note that `getRemoteCertificates()` returns raw DER-encoded X.509 certificates as `ArrayBuffer` objects. DER (Distinguished Encoding Rules) is the binary serialization format used for X.509 certificates in TLS and DTLS. Unlike {{domxref("RTCCertificate")}}, these buffers do not expose certificate fields (fingerprint, subject, validity period, and so on) directly. To work with them you must process the raw bytes: you can hash the buffer with {{domxref("SubtleCrypto.digest()")}} to compute a fingerprint (as shown in the example below), or pass it to an X.509 parsing library to inspect individual fields. ## Example ### Basic usage -This function shows how you might get and fingerprint the remote peer's certificate after the DTLS handshake, and compare it to a stored value. +This example shows how to fingerprint the remote peer's certificate after the DTLS handshake and compare it against a stored value. ```js async function getRemoteFingerprint(dtlsTransport) { @@ -80,6 +79,7 @@ pc.addEventListener("connectionstatechange", async () => { if (!sender?.transport) return; const fingerprint = await getRemoteFingerprint(sender.transport); + if (!fingerprint) return; const stored = localStorage.getItem("remote-peer-fingerprint"); if (!stored) { From 2baae04646acb5437db4f1d2bc37bf5fc36e1676 Mon Sep 17 00:00:00 2001 From: Hamish Willee Date: Fri, 26 Jun 2026 13:54:56 +1000 Subject: [PATCH 4/7] code review - easy suggestions Co-authored-by: Hamish Willee --- .../rtcdtlstransport/getremotecertificates/index.md | 13 +++++++++---- files/en-us/web/api/rtcdtlstransport/index.md | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md index 90be8fc66437518..6cb9554eeac4db2 100644 --- a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md +++ b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md @@ -8,7 +8,7 @@ browser-compat: api.RTCDtlsTransport.getRemoteCertificates {{APIRef("WebRTC")}} -The **`getRemoteCertificates()`** method of the {{domxref("RTCDtlsTransport")}} interface returns the certificates of the remote peer of the DTLS connection. +The **`getRemoteCertificates()`** method of the {{domxref("RTCDtlsTransport")}} interface returns the certificates chain of the remote peer of the DTLS connection. ## Syntax @@ -22,7 +22,8 @@ None. ### Return value -An array of {{jsxref("ArrayBuffer")}} objects, each containing a DER-encoded X.509 certificate of the remote peer. +An array of {{jsxref("ArrayBuffer")}} objects that represents the remote peer's certificate chain. +Each object contains a DER-encoded X.509 certificate. For [`new`](/en-US/docs/Web/API/RTCDtlsTransport/state#new) connections, this is an empty array. It is populated with the certificates from the remote peer when the state of the transport changes to [`connected`](/en-US/docs/Web/API/RTCDtlsTransport/state#connected). @@ -43,12 +44,15 @@ Establishing the identity of the remote peer usually requires an out-of-band mec The `getRemoteCertificates()` method allows you to get the remote certificates used by DTLS and use them for _application-layer_ authentication of the remote peer. -The way this works is that each peer must persist their own DTLS certificate across sessions, rather than generating a new one each time. +For fingerprint continuity, each peer must use the same certificate across sessions, rather than generating a new one each time they connect." After connecting to the remote peer, you'd exchange information out-of-band to verify that it is the intended party, and use `getRemoteCertificates()` to get its certificates. When you subsequently connect to that remote peer, you'd only allow communication if it has exactly the same certificate fingerprints. There is still a window for a person-in-the-middle attack, but it only exists for the very first connection between peers. -Note that `getRemoteCertificates()` returns raw DER-encoded X.509 certificates as `ArrayBuffer` objects. DER (Distinguished Encoding Rules) is the binary serialization format used for X.509 certificates in TLS and DTLS. Unlike {{domxref("RTCCertificate")}}, these buffers do not expose certificate fields (fingerprint, subject, validity period, and so on) directly. To work with them you must process the raw bytes: you can hash the buffer with {{domxref("SubtleCrypto.digest()")}} to compute a fingerprint (as shown in the example below), or pass it to an X.509 parsing library to inspect individual fields. +Note that `getRemoteCertificates()` returns raw DER-encoded X.509 certificates as `ArrayBuffer` objects. +DER (Distinguished Encoding Rules) is the binary serialization format used for X.509 certificates in TLS and DTLS. +Unlike {{domxref("RTCCertificate")}}, these buffers do not expose fingerprints and expiration date directly. +To work with them you must process the raw bytes: you can hash the buffer with {{domxref("SubtleCrypto.digest()")}} to compute a fingerprint (as shown in the example below), or pass it to an X.509 parsing library to inspect individual fields. ## Example @@ -102,5 +106,6 @@ pc.addEventListener("connectionstatechange", async () => { ## See also +- {{domxref("RTCPeerConnection.generateCertificate()")}} - [WebRTC API](/en-US/docs/Web/API/WebRTC_API) - [Introduction to the Real-time Transport Protocol (RTP)](/en-US/docs/Web/API/WebRTC_API/Intro_to_RTP) diff --git a/files/en-us/web/api/rtcdtlstransport/index.md b/files/en-us/web/api/rtcdtlstransport/index.md index 277d577bea0f8eb..759078c221bdf93 100644 --- a/files/en-us/web/api/rtcdtlstransport/index.md +++ b/files/en-us/web/api/rtcdtlstransport/index.md @@ -32,7 +32,7 @@ _Also inherits properties from {{DOMxRef("EventTarget")}}._ _Also inherits methods from {{DOMxRef("EventTarget")}}._ - {{DOMxRef("RTCDtlsTransport.getRemoteCertificates", "getRemoteCertificates()")}} - - : Returns an array of {{jsxref("ArrayBuffer")}} objects containing the certificates of the remote peer of the connection. + - : Returns an array of {{jsxref("ArrayBuffer")}} objects representing the remote peer's certificate chain. ## Events From 099570d167fc6a879157ee41bdc32543efe2aae9 Mon Sep 17 00:00:00 2001 From: Hamish Willee Date: Fri, 26 Jun 2026 14:08:32 +1000 Subject: [PATCH 5/7] code review - accept suggestion on handshake info Co-authored-by: Hamish Willee --- .../web/api/rtcdtlstransport/getremotecertificates/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md index 6cb9554eeac4db2..03e3aec1e3ecbeb 100644 --- a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md +++ b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md @@ -35,8 +35,8 @@ None ## Description WebRTC media and data channels are secured using DTLS (Datagram Transport Layer Security). -The protocol automatically uses certificates to ensure that the communicating remote peer is the same entity that negotiated the connection via the signaling server. -This is done by checking that the certificate presented during the DTLS handshake matches the `a=fingerprint` provided in the SDP. +During signaling, each endpoint advertises the fingerprint of the DTLS certificate it will present. +During the DTLS handshake, the user agent verifies that the certificate presented by the remote peer matches the fingerprint in the negotiated SDP. DTLS guarantees the connected peer is the one you've been negotiating with, because only that peer has the private key matching the certificate whose fingerprint was exchanged during signaling. However, it doesn't tell you who this remote peer is: DTLS can't help you if you initially connected to a compromised signaling server, or to some unexpected peer. From a63908432287f0390dc11ef6c1b0b5dad7d89f4d Mon Sep 17 00:00:00 2001 From: Hamish Willee Date: Fri, 26 Jun 2026 14:12:51 +1000 Subject: [PATCH 6/7] Apply suggestions from code review Co-authored-by: Hamish Willee --- .../web/api/rtcdtlstransport/getremotecertificates/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md index 03e3aec1e3ecbeb..cb92f5952c9d1dd 100644 --- a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md +++ b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md @@ -39,7 +39,7 @@ During signaling, each endpoint advertises the fingerprint of the DTLS certifica During the DTLS handshake, the user agent verifies that the certificate presented by the remote peer matches the fingerprint in the negotiated SDP. DTLS guarantees the connected peer is the one you've been negotiating with, because only that peer has the private key matching the certificate whose fingerprint was exchanged during signaling. -However, it doesn't tell you who this remote peer is: DTLS can't help you if you initially connected to a compromised signaling server, or to some unexpected peer. +However, WebRTC uses self-signed certificates rather than certificates issued by a certificate authority, so the certificate does not identify the person, service, or device at the other end. Establishing the identity of the remote peer usually requires an out-of-band mechanism such as comparing certificate fingerprints verbally over a phone call, or using a separate authenticated channel. The `getRemoteCertificates()` method allows you to get the remote certificates used by DTLS and use them for _application-layer_ authentication of the remote peer. From f662d027e8ec5be918454aafe63fe920088d6b2b Mon Sep 17 00:00:00 2001 From: Hamish Willee Date: Fri, 26 Jun 2026 14:13:54 +1000 Subject: [PATCH 7/7] Apply suggestion from @hamishwillee --- .../web/api/rtcdtlstransport/getremotecertificates/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md index cb92f5952c9d1dd..dca7e3835333f8e 100644 --- a/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md +++ b/files/en-us/web/api/rtcdtlstransport/getremotecertificates/index.md @@ -39,7 +39,7 @@ During signaling, each endpoint advertises the fingerprint of the DTLS certifica During the DTLS handshake, the user agent verifies that the certificate presented by the remote peer matches the fingerprint in the negotiated SDP. DTLS guarantees the connected peer is the one you've been negotiating with, because only that peer has the private key matching the certificate whose fingerprint was exchanged during signaling. -However, WebRTC uses self-signed certificates rather than certificates issued by a certificate authority, so the certificate does not identify the person, service, or device at the other end. +However, since WebRTC uses self-signed certificates rather than certificates issued by a certificate authority, the certificate does not identify the person, service, or device at the other end. Establishing the identity of the remote peer usually requires an out-of-band mechanism such as comparing certificate fingerprints verbally over a phone call, or using a separate authenticated channel. The `getRemoteCertificates()` method allows you to get the remote certificates used by DTLS and use them for _application-layer_ authentication of the remote peer.