diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index e6ad0da64c..fb08dd1971 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -492,6 +492,7 @@ generate_jni("generated_peerconnection_jni") { "api/org/webrtc/RtpReceiver.java", "api/org/webrtc/RtpSender.java", "api/org/webrtc/RtpTransceiver.java", + "api/org/webrtc/SSLCertificateVerifier.java", "api/org/webrtc/SdpObserver.java", "api/org/webrtc/SessionDescription.java", "api/org/webrtc/StatsObserver.java", @@ -578,6 +579,8 @@ rtc_static_library("peerconnection_jni") { "src/jni/pc/sdpobserver.h", "src/jni/pc/sessiondescription.cc", "src/jni/pc/sessiondescription.h", + "src/jni/pc/sslcertificateverifierwrapper.cc", + "src/jni/pc/sslcertificateverifierwrapper.h", "src/jni/pc/statsobserver.cc", "src/jni/pc/statsobserver.h", "src/jni/pc/turncustomizer.cc", @@ -990,6 +993,7 @@ rtc_android_library("peerconnection_java") { "api/org/webrtc/RtpReceiver.java", "api/org/webrtc/RtpSender.java", "api/org/webrtc/RtpTransceiver.java", + "api/org/webrtc/SSLCertificateVerifier.java", "api/org/webrtc/SdpObserver.java", "api/org/webrtc/SessionDescription.java", "api/org/webrtc/StatsObserver.java", diff --git a/sdk/android/api/org/webrtc/PeerConnectionDependencies.java b/sdk/android/api/org/webrtc/PeerConnectionDependencies.java index 8ecf0ff11e..fd765b17d1 100644 --- a/sdk/android/api/org/webrtc/PeerConnectionDependencies.java +++ b/sdk/android/api/org/webrtc/PeerConnectionDependencies.java @@ -20,18 +20,27 @@ import javax.annotation.Nullable; */ public final class PeerConnectionDependencies { // Mandatory dependencies. - private PeerConnection.Observer observer; + private final PeerConnection.Observer observer; + + // Optional fields. + private final SSLCertificateVerifier sslCertificateVerifier; public static class Builder { private PeerConnection.Observer observer; + private SSLCertificateVerifier sslCertificateVerifier; private Builder(PeerConnection.Observer observer) { this.observer = observer; } + public Builder setSSLCertificateVerifier(SSLCertificateVerifier sslCertificateVerifier) { + this.sslCertificateVerifier = sslCertificateVerifier; + return this; + } + // Observer is a required dependency and so is forced in the construction of the object. public PeerConnectionDependencies createPeerConnectionDependencies() { - return new PeerConnectionDependencies(observer); + return new PeerConnectionDependencies(observer, sslCertificateVerifier); } } @@ -43,7 +52,14 @@ public final class PeerConnectionDependencies { return observer; } - private PeerConnectionDependencies(PeerConnection.Observer observer) { + @Nullable + SSLCertificateVerifier getSSLCertificateVerifier() { + return sslCertificateVerifier; + } + + private PeerConnectionDependencies( + PeerConnection.Observer observer, SSLCertificateVerifier sslCertificateVerifier) { this.observer = observer; + this.sslCertificateVerifier = sslCertificateVerifier; } } diff --git a/sdk/android/api/org/webrtc/PeerConnectionFactory.java b/sdk/android/api/org/webrtc/PeerConnectionFactory.java index e4e881ff6f..3a76d7cb94 100644 --- a/sdk/android/api/org/webrtc/PeerConnectionFactory.java +++ b/sdk/android/api/org/webrtc/PeerConnectionFactory.java @@ -328,6 +328,25 @@ public class PeerConnectionFactory { this.nativeFactory = nativeFactory; } + /** + * Internal helper function to pass the parameters down into the native JNI bridge. + */ + @Nullable + PeerConnection createPeerConnectionInternal(PeerConnection.RTCConfiguration rtcConfig, + MediaConstraints constraints, PeerConnection.Observer observer, + SSLCertificateVerifier sslCertificateVerifier) { + long nativeObserver = PeerConnection.createNativePeerConnectionObserver(observer); + if (nativeObserver == 0) { + return null; + } + long nativePeerConnection = nativeCreatePeerConnection( + nativeFactory, rtcConfig, constraints, nativeObserver, sslCertificateVerifier); + if (nativePeerConnection == 0) { + return null; + } + return new PeerConnection(nativePeerConnection); + } + /** * Deprecated. PeerConnection constraints are deprecated. Supply values in rtcConfig struct * instead and use the method without constraints in the signature. @@ -336,16 +355,8 @@ public class PeerConnectionFactory { @Deprecated public PeerConnection createPeerConnection(PeerConnection.RTCConfiguration rtcConfig, MediaConstraints constraints, PeerConnection.Observer observer) { - long nativeObserver = PeerConnection.createNativePeerConnectionObserver(observer); - if (nativeObserver == 0) { - return null; - } - long nativePeerConnection = - nativeCreatePeerConnection(nativeFactory, rtcConfig, constraints, nativeObserver); - if (nativePeerConnection == 0) { - return null; - } - return new PeerConnection(nativePeerConnection); + return createPeerConnectionInternal( + rtcConfig, constraints, observer, /* sslCertificateVerifier= */ null); } /** @@ -376,7 +387,8 @@ public class PeerConnectionFactory { @Nullable public PeerConnection createPeerConnection( PeerConnection.RTCConfiguration rtcConfig, PeerConnectionDependencies dependencies) { - return createPeerConnection(rtcConfig, null /* constraints */, dependencies.getObserver()); + return createPeerConnectionInternal(rtcConfig, null /* constraints */, + dependencies.getObserver(), dependencies.getSSLCertificateVerifier()); } public MediaStream createLocalMediaStream(String label) { @@ -514,7 +526,8 @@ public class PeerConnectionFactory { VideoDecoderFactory decoderFactory, long nativeAudioProcessor, long nativeFecControllerFactory); private static native long nativeCreatePeerConnection(long factory, - PeerConnection.RTCConfiguration rtcConfig, MediaConstraints constraints, long nativeObserver); + PeerConnection.RTCConfiguration rtcConfig, MediaConstraints constraints, long nativeObserver, + SSLCertificateVerifier sslCertificateVerifier); private static native long nativeCreateLocalMediaStream(long factory, String label); private static native long nativeCreateVideoSource(long factory, boolean is_screencast); private static native long nativeCreateVideoTrack( diff --git a/sdk/android/api/org/webrtc/SSLCertificateVerifier.java b/sdk/android/api/org/webrtc/SSLCertificateVerifier.java new file mode 100644 index 0000000000..461cd3b143 --- /dev/null +++ b/sdk/android/api/org/webrtc/SSLCertificateVerifier.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc; + +/** + * The SSLCertificateVerifier interface allows API users to provide custom + * logic to verify certificates. + */ +public interface SSLCertificateVerifier { + /** + * Implementations of verify allow applications to provide custom logic for + * verifying certificates. This is not required by default and should be used + * with care. + * + * @param certificate A byte array containing a DER encoded X509 certificate. + * @return True if the certificate is verified and trusted else false. + */ + @CalledByNative boolean verify(byte[] certificate); +} diff --git a/sdk/android/src/jni/pc/peerconnectionfactory.cc b/sdk/android/src/jni/pc/peerconnectionfactory.cc index 889593e1c5..ba1be38453 100644 --- a/sdk/android/src/jni/pc/peerconnectionfactory.cc +++ b/sdk/android/src/jni/pc/peerconnectionfactory.cc @@ -34,6 +34,7 @@ #include "sdk/android/src/jni/pc/media.h" #include "sdk/android/src/jni/pc/ownedfactoryandthreads.h" #include "sdk/android/src/jni/pc/peerconnection.h" +#include "sdk/android/src/jni/pc/sslcertificateverifierwrapper.h" #include "sdk/android/src/jni/pc/video.h" #include "system_wrappers/include/field_trial.h" // Adding 'nogncheck' to disable the gn include headers check. @@ -374,7 +375,8 @@ static jlong JNI_PeerConnectionFactory_CreatePeerConnection( jlong factory, const JavaParamRef& j_rtc_config, const JavaParamRef& j_constraints, - jlong observer_p) { + jlong observer_p, + const JavaParamRef& j_sslCertificateVerifier) { rtc::scoped_refptr f( reinterpret_cast( factoryFromJava(factory))); @@ -404,8 +406,17 @@ static jlong JNI_PeerConnectionFactory_CreatePeerConnection( constraints = JavaToNativeMediaConstraints(jni, j_constraints); CopyConstraintsIntoRtcConfiguration(constraints.get(), &rtc_config); } - rtc::scoped_refptr pc( - f->CreatePeerConnection(rtc_config, nullptr, nullptr, observer.get())); + + PeerConnectionDependencies peer_connection_dependencies(observer.get()); + if (!j_sslCertificateVerifier.is_null()) { + peer_connection_dependencies.tls_cert_verifier = + absl::make_unique( + jni, j_sslCertificateVerifier); + } + + rtc::scoped_refptr pc(f->CreatePeerConnection( + rtc_config, std::move(peer_connection_dependencies))); + return jlongFromPointer( new OwnedPeerConnection(pc, std::move(observer), std::move(constraints))); } diff --git a/sdk/android/src/jni/pc/sslcertificateverifierwrapper.cc b/sdk/android/src/jni/pc/sslcertificateverifierwrapper.cc new file mode 100644 index 0000000000..2ff9a462e3 --- /dev/null +++ b/sdk/android/src/jni/pc/sslcertificateverifierwrapper.cc @@ -0,0 +1,44 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "sdk/android/src/jni/pc/sslcertificateverifierwrapper.h" +#include "sdk/android/generated_peerconnection_jni/jni/SSLCertificateVerifier_jni.h" +#include "sdk/android/native_api/jni/class_loader.h" +#include "sdk/android/native_api/jni/java_types.h" + +namespace webrtc { +namespace jni { + +SSLCertificateVerifierWrapper::SSLCertificateVerifierWrapper( + JNIEnv* jni, + const JavaRef& ssl_certificate_verifier) + : ssl_certificate_verifier_(jni, ssl_certificate_verifier) {} + +SSLCertificateVerifierWrapper::~SSLCertificateVerifierWrapper() = default; + +bool SSLCertificateVerifierWrapper::Verify( + const rtc::SSLCertificate& certificate) { + JNIEnv* jni = AttachCurrentThreadIfNeeded(); + + // Serialize the der encoding of the cert into a jbyteArray + rtc::Buffer cert_der_buffer; + certificate.ToDER(&cert_der_buffer); + ScopedJavaLocalRef jni_buffer( + jni, jni->NewByteArray(cert_der_buffer.size())); + jni->SetByteArrayRegion( + jni_buffer.obj(), 0, cert_der_buffer.size(), + reinterpret_cast(cert_der_buffer.data())); + + return Java_SSLCertificateVerifier_verify(jni, ssl_certificate_verifier_, + jni_buffer); +} + +} // namespace jni +} // namespace webrtc diff --git a/sdk/android/src/jni/pc/sslcertificateverifierwrapper.h b/sdk/android/src/jni/pc/sslcertificateverifierwrapper.h new file mode 100644 index 0000000000..719fa44494 --- /dev/null +++ b/sdk/android/src/jni/pc/sslcertificateverifierwrapper.h @@ -0,0 +1,41 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef SDK_ANDROID_SRC_JNI_PC_SSLCERTIFICATEVERIFIERWRAPPER_H_ +#define SDK_ANDROID_SRC_JNI_PC_SSLCERTIFICATEVERIFIERWRAPPER_H_ + +#include +#include + +#include "rtc_base/sslcertificate.h" +#include "sdk/android/src/jni/jni_helpers.h" + +namespace webrtc { +namespace jni { + +// Wrapper for Java SSLCertifiacteVerifier class. Delegates method calls through +// JNI and wraps the encoder inside SSLCertificateVerifierWrapper. +class SSLCertificateVerifierWrapper : public rtc::SSLCertificateVerifier { + public: + SSLCertificateVerifierWrapper( + JNIEnv* jni, + const JavaRef& ssl_certificate_verifier); + ~SSLCertificateVerifierWrapper() override; + + bool Verify(const rtc::SSLCertificate& certificate) override; + + private: + const ScopedJavaGlobalRef ssl_certificate_verifier_; +}; + +} // namespace jni +} // namespace webrtc + +#endif // SDK_ANDROID_SRC_JNI_PC_SSLCERTIFICATEVERIFIERWRAPPER_H_