From e6c92fee0556b5665bfed09657e7c53c0bba114e Mon Sep 17 00:00:00 2001 From: pedro Date: Thu, 8 Feb 2024 23:13:06 +0100 Subject: [PATCH] implement addCertificates for TLS connection --- .../com/pedro/common/AcceptAllCertificates.kt | 31 +++++++++++++++++++ .../java/com/pedro/common/TLSSocketFactory.kt | 9 ++++-- .../util/streamclient/GenericStreamClient.kt | 9 ++++++ .../util/streamclient/RtmpStreamClient.kt | 8 +++++ .../util/streamclient/RtspStreamClient.kt | 7 +++++ .../java/com/pedro/rtmp/rtmp/RtmpClient.kt | 11 ++++++- .../com/pedro/rtmp/utils/socket/TcpSocket.kt | 10 ++++-- .../java/com/pedro/rtsp/rtsp/RtspClient.kt | 11 ++++++- 8 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 common/src/main/java/com/pedro/common/AcceptAllCertificates.kt diff --git a/common/src/main/java/com/pedro/common/AcceptAllCertificates.kt b/common/src/main/java/com/pedro/common/AcceptAllCertificates.kt new file mode 100644 index 000000000..65288e7d1 --- /dev/null +++ b/common/src/main/java/com/pedro/common/AcceptAllCertificates.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 pedroSG94. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.pedro.common + +import android.annotation.SuppressLint +import java.security.cert.X509Certificate +import javax.net.ssl.X509TrustManager + +/** + * Created by pedro on 8/2/24. + */ +@SuppressLint("TrustAllX509TrustManager", "CustomX509TrustManager") +class AcceptAllCertificates: X509TrustManager { + override fun checkClientTrusted(chain: Array?, authType: String?) {} + override fun checkServerTrusted(chain: Array?, authType: String?) {} + override fun getAcceptedIssuers(): Array? = null +} \ No newline at end of file diff --git a/common/src/main/java/com/pedro/common/TLSSocketFactory.kt b/common/src/main/java/com/pedro/common/TLSSocketFactory.kt index c7e85f910..54790bdca 100644 --- a/common/src/main/java/com/pedro/common/TLSSocketFactory.kt +++ b/common/src/main/java/com/pedro/common/TLSSocketFactory.kt @@ -20,20 +20,25 @@ import java.io.IOException import java.net.InetAddress import java.net.Socket import java.net.UnknownHostException +import java.security.SecureRandom import javax.net.ssl.SSLContext import javax.net.ssl.SSLSocket import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.TrustManager /** * @author fkrauthan */ -open class TLSSocketFactory : SSLSocketFactory() { +open class TLSSocketFactory( + trustManagers: Array? = null +): SSLSocketFactory() { private val internalSSLSocketFactory: SSLSocketFactory init { val context = SSLContext.getInstance("TLS") - context.init(null, null, null) + val secureRandom = if (trustManagers != null) SecureRandom() else null + context.init(null, trustManagers, secureRandom) internalSSLSocketFactory = context.socketFactory } diff --git a/library/src/main/java/com/pedro/library/util/streamclient/GenericStreamClient.kt b/library/src/main/java/com/pedro/library/util/streamclient/GenericStreamClient.kt index 8c3aeabb9..62525954f 100644 --- a/library/src/main/java/com/pedro/library/util/streamclient/GenericStreamClient.kt +++ b/library/src/main/java/com/pedro/library/util/streamclient/GenericStreamClient.kt @@ -18,6 +18,7 @@ package com.pedro.library.util.streamclient import com.pedro.rtsp.rtsp.Protocol import com.pedro.srt.srt.packets.control.handshake.EncryptionType +import javax.net.ssl.TrustManager /** * Created by pedro on 12/10/23. @@ -30,6 +31,14 @@ class GenericStreamClient( private var connectedStreamClient : StreamBaseClient? = null + /** + * Add certificates for TLS connection + */ + fun addCertificates(certificates: Array?) { + rtmpClient.addCertificates(certificates) + rtspClient.addCertificates(certificates) + } + /** * Set passphrase for encrypt. Use empty value to disable it. */ diff --git a/library/src/main/java/com/pedro/library/util/streamclient/RtmpStreamClient.kt b/library/src/main/java/com/pedro/library/util/streamclient/RtmpStreamClient.kt index 1de8496c9..aa4d66c93 100644 --- a/library/src/main/java/com/pedro/library/util/streamclient/RtmpStreamClient.kt +++ b/library/src/main/java/com/pedro/library/util/streamclient/RtmpStreamClient.kt @@ -17,6 +17,7 @@ package com.pedro.library.util.streamclient import com.pedro.rtmp.rtmp.RtmpClient +import javax.net.ssl.TrustManager /** * Created by pedro on 12/10/23. @@ -26,6 +27,13 @@ class RtmpStreamClient( private val streamClientListener: StreamClientListener? ): StreamBaseClient() { + /** + * Add certificates for TLS connection + */ + fun addCertificates(certificates: Array?) { + rtmpClient.addCertificates(certificates) + } + /** * Some Livestream hosts use Akamai auth that requires RTMP packets to be sent with increasing * timestamp order regardless of packet type. diff --git a/library/src/main/java/com/pedro/library/util/streamclient/RtspStreamClient.kt b/library/src/main/java/com/pedro/library/util/streamclient/RtspStreamClient.kt index db0873123..737b7168c 100644 --- a/library/src/main/java/com/pedro/library/util/streamclient/RtspStreamClient.kt +++ b/library/src/main/java/com/pedro/library/util/streamclient/RtspStreamClient.kt @@ -18,6 +18,7 @@ package com.pedro.library.util.streamclient import com.pedro.rtsp.rtsp.Protocol import com.pedro.rtsp.rtsp.RtspClient +import javax.net.ssl.TrustManager /** * Created by pedro on 12/10/23. @@ -27,6 +28,12 @@ class RtspStreamClient( private val streamClientListener: StreamClientListener? ): StreamBaseClient() { + /** + * Add certificates for TLS connection + */ + fun addCertificates(certificates: Array?) { + rtspClient.addCertificates(certificates) + } /** * Internet protocol used. diff --git a/rtmp/src/main/java/com/pedro/rtmp/rtmp/RtmpClient.kt b/rtmp/src/main/java/com/pedro/rtmp/rtmp/RtmpClient.kt index f18833530..b648c78d1 100644 --- a/rtmp/src/main/java/com/pedro/rtmp/rtmp/RtmpClient.kt +++ b/rtmp/src/main/java/com/pedro/rtmp/rtmp/RtmpClient.kt @@ -45,6 +45,7 @@ import java.io.* import java.net.* import java.nio.ByteBuffer import java.util.regex.Pattern +import javax.net.ssl.TrustManager /** * Created by pedro on 8/04/21. @@ -69,6 +70,7 @@ class RtmpClient(private val connectChecker: ConnectChecker) { private var url: String? = null private var tlsEnabled = false + private var certificates: Array? = null private var tunneled = false private var doingRetry = false @@ -89,6 +91,13 @@ class RtmpClient(private val connectChecker: ConnectChecker) { val sentVideoFrames: Long get() = rtmpSender.getSentVideoFrames() + /** + * Add certificates for TLS connection + */ + fun addCertificates(certificates: Array?) { + this.certificates = certificates + } + fun setVideoCodec(videoCodec: VideoCodec) { if (!isStreaming) { commandsManager.videoCodec = videoCodec @@ -311,7 +320,7 @@ class RtmpClient(private val connectChecker: ConnectChecker) { val socket = if (tunneled) { TcpTunneledSocket(commandsManager.host, commandsManager.port, tlsEnabled) } else { - TcpSocket(commandsManager.host, commandsManager.port, tlsEnabled) + TcpSocket(commandsManager.host, commandsManager.port, tlsEnabled, certificates) } this.socket = socket socket.connect() diff --git a/rtmp/src/main/java/com/pedro/rtmp/utils/socket/TcpSocket.kt b/rtmp/src/main/java/com/pedro/rtmp/utils/socket/TcpSocket.kt index 5bc017702..00590286a 100644 --- a/rtmp/src/main/java/com/pedro/rtmp/utils/socket/TcpSocket.kt +++ b/rtmp/src/main/java/com/pedro/rtmp/utils/socket/TcpSocket.kt @@ -26,11 +26,17 @@ import java.net.InetSocketAddress import java.net.Socket import java.net.SocketAddress import java.security.GeneralSecurityException +import javax.net.ssl.TrustManager /** * Created by pedro on 5/4/22. */ -class TcpSocket(private val host: String, private val port: Int, private val secured: Boolean): RtmpSocket() { +class TcpSocket( + private val host: String, + private val port: Int, + private val secured: Boolean, + private val certificates: Array? +): RtmpSocket() { private var socket: Socket = Socket() private var input = ByteArrayInputStream(byteArrayOf()).buffered() @@ -47,7 +53,7 @@ class TcpSocket(private val host: String, private val port: Int, private val sec override fun connect() { if (secured) { try { - val socketFactory = TLSSocketFactory() + val socketFactory = TLSSocketFactory(certificates) socket = socketFactory.createSocket(host, port) } catch (e: GeneralSecurityException) { throw IOException("Create SSL socket failed: ${e.message}") diff --git a/rtsp/src/main/java/com/pedro/rtsp/rtsp/RtspClient.kt b/rtsp/src/main/java/com/pedro/rtsp/rtsp/RtspClient.kt index 3337978e2..beeaefa2b 100644 --- a/rtsp/src/main/java/com/pedro/rtsp/rtsp/RtspClient.kt +++ b/rtsp/src/main/java/com/pedro/rtsp/rtsp/RtspClient.kt @@ -44,6 +44,7 @@ import java.net.SocketTimeoutException import java.nio.ByteBuffer import java.security.GeneralSecurityException import java.util.regex.Pattern +import javax.net.ssl.TrustManager /** * Created by pedro on 10/02/17. @@ -70,6 +71,7 @@ class RtspClient(private val connectChecker: ConnectChecker) { //for secure transport private var tlsEnabled = false + private var certificates: Array? = null private val rtspSender: RtspSender = RtspSender(connectChecker) private var url: String? = null private val commandsManager: CommandsManager = CommandsManager() @@ -90,6 +92,13 @@ class RtspClient(private val connectChecker: ConnectChecker) { val sentVideoFrames: Long get() = rtspSender.getSentVideoFrames() + /** + * Add certificates for TLS connection + */ + fun addCertificates(certificates: Array?) { + this.certificates = certificates + } + /** * Check periodically if server is alive using Echo protocol. */ @@ -227,7 +236,7 @@ class RtspClient(private val connectChecker: ConnectChecker) { connectionSocket?.connect(socketAddress, 5000) } else { try { - val socketFactory = TLSSocketFactory() + val socketFactory = TLSSocketFactory(certificates) connectionSocket = socketFactory.createSocket(host, port) } catch (e: GeneralSecurityException) { throw IOException("Create SSL socket failed: ${e.message}")