From 0af1e765552f52029f0d3d2668016b28f4e76e76 Mon Sep 17 00:00:00 2001 From: Alex Andres Date: Mon, 26 Oct 2026 15:28:51 +0100 Subject: [PATCH] fix: return no remote certificates before the DTLS handshake --- .../src/main/cpp/src/JNI_RTCDtlsTransport.cpp | 3 +- .../dev/onvoid/webrtc/RTCDtlsTransport.java | 3 +- .../onvoid/webrtc/RTCDtlsTransportTests.java | 39 +++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/webrtc-jni/src/main/cpp/src/JNI_RTCDtlsTransport.cpp b/webrtc-jni/src/main/cpp/src/JNI_RTCDtlsTransport.cpp index 24daf06cf..1c1d8bf99 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_RTCDtlsTransport.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_RTCDtlsTransport.cpp @@ -69,7 +69,8 @@ JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_RTCDtlsTransport_getRemoteCerti auto info = transport->Information(); auto certChain = info.remote_ssl_certificates(); - size_t count = certChain->GetSize(); + // There is no chain before the handshake has received one. + size_t count = certChain != nullptr ? certChain->GetSize() : 0; jni::JavaArrayList certificates(env, count); diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/RTCDtlsTransport.java b/webrtc/src/main/java/dev/onvoid/webrtc/RTCDtlsTransport.java index 14b7315ff..ca1b49064 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/RTCDtlsTransport.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/RTCDtlsTransport.java @@ -64,7 +64,8 @@ public class RTCDtlsTransport extends NativeObject { /** * Returns the certificate chain in use by the remote side, with each - * certificate encoded in PEM format. + * certificate encoded in PEM format. The list is empty until the DTLS + * handshake has received the certificates of the remote side. * * @return The certificate chain in use by the remote side. */ diff --git a/webrtc/src/test/java/dev/onvoid/webrtc/RTCDtlsTransportTests.java b/webrtc/src/test/java/dev/onvoid/webrtc/RTCDtlsTransportTests.java index e9e82c450..02d2c1d0f 100644 --- a/webrtc/src/test/java/dev/onvoid/webrtc/RTCDtlsTransportTests.java +++ b/webrtc/src/test/java/dev/onvoid/webrtc/RTCDtlsTransportTests.java @@ -18,7 +18,9 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.Collections; @@ -127,6 +129,43 @@ public void onError(String error) { } "The replaced observer must not receive further events"); } + @Test + void remoteCertificates() { + List certificates = transport.getRemoteCertificates(); + + assertFalse(certificates.isEmpty()); + + for (RTCCertificatePEM certificate : certificates) { + assertTrue(certificate.getCertificate().startsWith("-----BEGIN CERTIFICATE-----")); + } + } + + @Test + void remoteCertificatesBeforeHandshake() throws Exception { + TestPeerConnection offerer = new TestPeerConnection(factory); + + try { + AudioTrackSource audioSource = factory.createAudioSource(new AudioOptions()); + AudioTrack audioTrack = factory.createAudioTrack("audioTrack", audioSource); + RTCRtpSender audioSender = offerer.getPeerConnection() + .addTrack(audioTrack, Collections.singletonList("stream1")); + + // Setting the local description creates the transport, which has + // no remote certificates before the handshake. Reading them used + // to crash the VM. + offerer.createOffer(); + + RTCDtlsTransport dtlsTransport = audioSender.getTransport(); + assertNotNull(dtlsTransport); + assertEquals(RTCDtlsTransportState.NEW, dtlsTransport.getState()); + + assertTrue(dtlsTransport.getRemoteCertificates().isEmpty()); + } + finally { + offerer.close(); + } + } + @Test void observerCanUseRtpSender() throws Exception { // WebRTC reports DTLS states on the network thread, which is also the