Start · Sprachen · JavaScript · Referenz · RTCDtlsTransport.getRemoteCertificates()

RTCDtlsTransport.getRemoteCertificates()

Methode

Gibt die Zertifikatskette des entfernten Peers einer DTLS-Verbindung als Array von DER-kodierten <code>ArrayBuffer</code>-Objekten zurück.

seit JavaScript Chromium-Browser (Chrome/Edge 72+); in Firefox und Kategorie: webapi

Signatur

RTCDtlsTransport.prototype.getRemoteCertificates()

Beschreibung

Die Methode getRemoteCertificates() des Interfaces RTCDtlsTransport liefert die Zertifikate, die der entfernte Peer beim DTLS-Handshake vorgelegt hat. Jedes Zertifikat liegt als ArrayBuffer mit den rohen DER-kodierten Bytes vor. Bei WebRTC ist das meist ein einzelnes selbstsigniertes Zertifikat.

Einsatzgebiete sind vor allem Diagnose, Protokollierung und eigene Identitätsprüfungen. Du kannst zum Beispiel den SHA-256-Fingerabdruck des Zertifikats selbst berechnen und mit der Zeile a=fingerprint aus der entfernten SDP vergleichen. Oder du gleichst ihn mit einem Fingerabdruck ab, den du über einen vertrauenswürdigen Kanal bekommen hast. So lassen sich Man-in-the-Middle-Angriffe über einen kompromittierten Signalisierungsserver erkennen.

An das RTCDtlsTransport-Objekt kommst du über RTCRtpSender.transport, RTCRtpReceiver.transport oder RTCSctpTransport.transport (bei Datenkanälen über pc.sctp.transport). Sinnvolle Daten gibt es erst, wenn der Handshake abgeschlossen ist, also wenn transport.state den Wert "connected" hat.

Rückgabewert

Typ
ArrayBuffer[]
Beschreibung
Ein Array mit den DER-kodierten Zertifikaten des entfernten Peers. Das erste Element ist das Zertifikat des Peers selbst. Solange der DTLS-Handshake nicht abgeschlossen ist, ist das Array leer.

Beispiele

Zertifikate nach dem Verbindungsaufbau auslesen

const pc = new RTCPeerConnection();
pc.addTransceiver('audio');
// ... Signalisierung (Offer/Answer, ICE) wie gewohnt ...

const dtls = pc.getSenders()[0].transport;

dtls.addEventListener('statechange', () => {
  if (dtls.state === 'connected') {
    const certs = dtls.getRemoteCertificates();
    console.log('Anzahl Zertifikate:', certs.length);
    console.log('Größe des ersten Zertifikats:', certs[0].byteLength, 'Bytes');
  }
});
Anzahl Zertifikate: 1 Größe des ersten Zertifikats: 396 Bytes

SHA-256-Fingerabdruck berechnen und mit der SDP vergleichen

const fingerprintOf = async (derBuffer) => {
  const hash = await crypto.subtle.digest('SHA-256', derBuffer);
  return [...new Uint8Array(hash)]
    .map((b) => b.toString(16).padStart(2, '0').toUpperCase())
    .join(':');
};

const verifyRemoteFingerprint = async (pc) => {
  const dtls = pc.getReceivers()[0]?.transport;
  if (!dtls || dtls.state !== 'connected') return false;

  const [cert] = dtls.getRemoteCertificates();
  const actual = await fingerprintOf(cert);

  const match = pc.remoteDescription.sdp.match(/a=fingerprint:sha-256 ([0-9A-F:]+)/i);
  const expected = match?.[1].toUpperCase();

  console.log('Berechnet:', actual);
  console.log('Aus SDP:  ', expected);
  return actual === expected;
};

// Aufruf, z. B. im connectionstatechange-Handler:
// console.log('Fingerabdruck stimmt:', await verifyRemoteFingerprint(pc));
Berechnet: 3A:7F:...:C2 Aus SDP: 3A:7F:...:C2 Fingerabdruck stimmt: true

Zertifikat als PEM exportieren (z. B. für Logs)

const toPem = (derBuffer) => {
  const bytes = new Uint8Array(derBuffer);
  let binary = '';
  bytes.forEach((b) => { binary += String.fromCharCode(b); });
  const base64 = btoa(binary).match(/.{1,64}/g).join('\n');
  return `-----BEGIN CERTIFICATE-----\n${base64}\n-----END CERTIFICATE-----`;
};

const dtls = pc.sctp?.transport; // DTLS-Transport des Datenkanals
if (dtls?.state === 'connected') {
  dtls.getRemoteCertificates().forEach((cert, i) => {
    console.log(`Zertifikat ${i}:\n${toPem(cert)}`);
  });
}
Zertifikat 0: -----BEGIN CERTIFICATE----- MIIBFjCBvaADAgECAgkA... -----END CERTIFICATE-----

// Wichtig · Fallstricke

  • Zeitpunkt: Vor Abschluss des DTLS-Handshakes (state ist "new" oder "connecting") liefert die Methode ein leeres Array. Warte deshalb auf das Ereignis statechange mit state === "connected".
  • Browser-Kompatibilität: Unterstützt wird die Methode vor allem in Chromium-basierten Browsern (Chrome, Edge, Opera). Firefox implementiert sie nicht, und die Unterstützung in Safari ist uneinheitlich. Prüfe sie vorher per Feature-Erkennung: typeof RTCDtlsTransport !== 'undefined' && 'getRemoteCertificates' in RTCDtlsTransport.prototype.
  • Rohdaten: Die Rückgabe enthält nur DER-Bytes. Einen eingebauten X.509-Parser gibt es nicht. Für Felder wie Ablaufdatum oder Subject brauchst du eine Bibliothek (z. B. pkijs) oder einen eigenen ASN.1-Parser.
  • Sicherheit: WebRTC-Zertifikate sind meist selbstsigniert und haben keine vertrauenswürdige Zertifizierungsstelle. Echten Schutz vor Man-in-the-Middle-Angriffen bietet ein Fingerabdruckvergleich nur, wenn der erwartete Wert über einen anderen vertrauenswürdigen Kanal kommt als die SDP.
  • Bei bundlePolicy: "max-bundle" teilen sich alle Sender, Empfänger und der Datenkanal meist einen einzigen RTCDtlsTransport.