Start · Sprachen · JavaScript · Referenz · RTCCertificate

RTCCertificate

Schnittstelle

Stellt ein Zertifikat samt privatem Schlüssel dar, mit dem sich eine <code>RTCPeerConnection</code> beim DTLS-Handshake gegenüber der Gegenseite ausweist.

seit JavaScript Baseline: alle modernen Browser (getFingerprints() Kategorie: webapi

Signatur

interface RTCCertificate

Beschreibung

RTCCertificate stellt ein X.509-Zertifikat mit dem zugehörigen privaten Schlüssel dar. Eine RTCPeerConnection braucht es für den DTLS-Handshake, über den die Schlüssel für die verschlüsselten Medien- und Datenkanäle (SRTP bzw. SCTP) ausgehandelt werden. Den privaten Schlüssel kann JavaScript nicht lesen. Er bleibt im Browser.

Einen Konstruktor gibt es nicht. Instanzen erzeugst du über die statische Methode RTCPeerConnection.generateCertificate(). Das Zertifikat übergibst du dann im Konfigurationsobjekt unter certificates. Ohne diese Angabe erzeugt der Browser für jede Verbindung selbst ein neues Zertifikat.

Wichtige Bestandteile:

  • expires (nur lesbar, number): Ablaufzeitpunkt in Millisekunden seit der Unix-Epoche. Nach diesem Zeitpunkt lehnt der Browser das Zertifikat für neue Verbindungen ab.
  • getFingerprints(): Gibt ein Array von RTCDtlsFingerprint-Objekten zurück, jeweils mit algorithm (z. B. "sha-256") und value (Hex-Zeichenfolge mit Doppelpunkten). Diese Werte erscheinen auch in der SDP als a=fingerprint.

RTCCertificate ist serialisierbar. Du kannst es also in IndexedDB speichern und später wiederverwenden. So bleibt der Fingerabdruck über mehrere Sitzungen gleich, und die Gegenseite kann ihn zum Beispiel zur Identitätsprüfung oder zum Zertifikat-Pinning nutzen.

Parameter

Name Typ Default Beschreibung
$keygenAlgorithm Pflicht string | RsaHashedKeyGenParams | EcKeyGenParams Parameter für RTCPeerConnection.generateCertificate(), das Instanzen dieses Interfaces erzeugt. Browser müssen mindestens { name: "ECDSA", namedCurve: "P-256" } und { name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" } unterstützen. Optional kannst du mit expires (in Millisekunden) die Gültigkeitsdauer festlegen.

Beispiele

Zertifikat erzeugen und in einer Verbindung verwenden

const cert = await RTCPeerConnection.generateCertificate({
  name: 'ECDSA',
  namedCurve: 'P-256'
});

console.log('Läuft ab am:', new Date(cert.expires).toISOString());

const pc = new RTCPeerConnection({
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
  certificates: [cert]
});

console.log(pc.getConfiguration().certificates.length);
Läuft ab am: 2025-07-14T10:22:31.000Z 1

Fingerabdruck auslesen und mit der SDP vergleichen

const cert = await RTCPeerConnection.generateCertificate({
  name: 'RSASSA-PKCS1-v1_5',
  modulusLength: 2048,
  publicExponent: new Uint8Array([1, 0, 1]),
  hash: 'SHA-256'
});

const [fp] = cert.getFingerprints();
console.log(fp.algorithm, fp.value);

const pc = new RTCPeerConnection({ certificates: [cert] });
pc.createDataChannel('chat');
const offer = await pc.createOffer();

// Der Fingerabdruck steht als a=fingerprint in der SDP
const inSdp = offer.sdp.toLowerCase().includes(fp.value.toLowerCase());
console.log('In SDP enthalten:', inSdp);
sha-256 3A:9F:...:C1 In SDP enthalten: true

Zertifikat in IndexedDB speichern und wiederverwenden

const openDb = () => new Promise((resolve, reject) => {
  const req = indexedDB.open('webrtc', 1);
  req.onupgradeneeded = () => req.result.createObjectStore('certs');
  req.onsuccess = () => resolve(req.result);
  req.onerror = () => reject(req.error);
});

const idbRequest = (req) => new Promise((resolve, reject) => {
  req.onsuccess = () => resolve(req.result);
  req.onerror = () => reject(req.error);
});

const getCertificate = async () => {
  const db = await openDb();
  const stored = await idbRequest(
    db.transaction('certs').objectStore('certs').get('main')
  );

  // Noch gültig? Mit Puffer von einem Tag
  if (stored && stored.expires > Date.now() + 86_400_000) {
    return stored;
  }

  const cert = await RTCPeerConnection.generateCertificate({
    name: 'ECDSA',
    namedCurve: 'P-256'
  });
  await idbRequest(
    db.transaction('certs', 'readwrite').objectStore('certs').put(cert, 'main')
  );
  return cert;
};

const cert = await getCertificate();
const pc = new RTCPeerConnection({ certificates: [cert] });
console.log('Fingerabdruck:', cert.getFingerprints()[0].value);
Fingerabdruck: 7B:12:...:E4

// Wichtig · Fallstricke

  • Kein Konstruktor: new RTCCertificate() wirft einen TypeError. Erzeuge Instanzen ausschließlich über RTCPeerConnection.generateCertificate().
  • Konfiguration nicht nachträglich änderbar: Zertifikate legst du beim Erzeugen der RTCPeerConnection fest. Wenn setConfiguration() abweichende certificates erhält, wirft der Aufruf einen InvalidModificationError.
  • Ablauf: Laut Spezifikation darf ein Zertifikat höchstens 365 Tage gültig sein, standardmäßig sind es 30 Tage. Abgelaufene Zertifikate führen beim Erzeugen der Verbindung zu einem Fehler. Prüfe deshalb expires, bevor du ein gespeichertes Zertifikat wiederverwendest.
  • Datenschutz: Ein dauerhaft gespeichertes Zertifikat hat einen gleichbleibenden Fingerabdruck. Darüber lässt sich ein Nutzer wiedererkennen, ähnlich wie mit einem Cookie. Setze langlebige Zertifikate nur bewusst ein.
  • Sicherheit: Der Fingerabdruck schützt nur dann vor Man-in-the-Middle-Angriffen, wenn die SDP über einen vertrauenswürdigen, verschlüsselten Signalisierungskanal übertragen wird.
  • Kompatibilität: expires und generateCertificate() werden breit unterstützt. getFingerprints() kam in einigen Browsern (u. a. älteren Firefox-Versionen) erst spät oder fehlt dort. Prüfe die Methode vor der Nutzung mit typeof cert.getFingerprints === 'function'. Welche Algorithmen außer ECDSA P-256 und RSA unterstützt werden, hängt vom Browser ab.