awslabs / amazon-kinesis-video-streams-webrtc-sdk-android

Android SDK for interfacing with Amazon Kinesis Video Streams Signaling Service.
Apache License 2.0
58 stars 37 forks source link

Failed SSL handshake #74

Closed nickhuangcyh closed 2 years ago

nickhuangcyh commented 2 years ago

Hi, there.

I try to use KVS service on Android device. I use Tyrus framework to connect to KVS-Websocket server like sample code did. but sometimes it came SSL handshake has failed exception. (https://stackoverflow.com/questions/42051411/tyrus-websocket-ssl-handshake-has-failed) sample code : https://github.com/awslabs/amazon-kinesis-video-streams-webrtc-sdk-android

So I replace Tyrus with other websocket clients (Okhttp3, Java-WebSocket) Okhttp3 - https://github.com/square/okhttp Java-WebSocket - https://github.com/TooTallNate/Java-WebSocket

But I got 403 Forbidden when I tried to connect to KVS-Websocket server I also tried to use 'Okhttp3'/'Java-WebSocket' to connect to websocket service of coinbase (wss://ws-feed.pro.coinbase.com) and it works perfectly.

Is it possible to replace Tyrus with other websocket clients?

(Headers) {

Connection: "Upgrade",

Host: "v-a8xxxxxx.kinesisvideo.ap-southeast-1.amazonaws.com",

Origin: "v-a8xxxxxx.kinesisvideo.ap-southeast-1.amazonaws.com",

Sec-WebSocket-Key: "TsxxxxxxxxxxxxxxxxxxxxOA==",

Sec-WebSocket-Version="13",

Upgrade="websocket"

}

Thanks & Regards

nickhuangcyh commented 2 years ago

I think the problem is that WSS URI is encoded twice and the 'tyrus' is work perfectly on that, but not 'okhttp' and 'Java-WebSocket'

  1. All query params are encoded in buildQueryParamsMap function (e.g. '/' -> '%2F')
  2. URI init will encode it again (e.g. '%' -> '%25' '%2F' -> '%252F')

Here is my solution below

AwsV4Signer.kt

fun sign(
        uri: URI, accessKey: String, secretKey: String,
        sessionToken: String, wssUri: URI, region: String
    ): URI? {
        val dateMilli = Date().time
        val amzDate = getTimeStamp(dateMilli)
        val datestamp = getDateStamp(dateMilli)
        val queryParamsMap =
            buildQueryParamsMap(uri, accessKey, sessionToken, region, amzDate, datestamp)
        val canonicalQuerystring = getCanonicalizedQueryString(queryParamsMap)
        val canonicalRequest = getCanonicalRequest(uri, canonicalQuerystring)
        val stringToSign =
            signString(amzDate, createCredentialScope(region, datestamp), canonicalRequest)
        val signatureKey = getSignatureKey(secretKey, datestamp, region, SERVICE)
        val signature = BinaryUtils.toHex(hmacSha256(stringToSign, signatureKey))
        val signedCanonicalQueryString =
            canonicalQuerystring + "&" + X_AMZ_SIGNATURE + "=" + signature
        var uriResult: URI? = null
        try {
-           uriResult = URI(
-                  wssUri.scheme,
-                  wssUri.rawAuthority,
-                  getCanonicalUri(uri),
-                  signedCanonicalQueryString,
-                  null
-           )
+           val scheme = wssUri.scheme
+           val rawAuthority = wssUri.rawAuthority
+           val path = getCanonicalUri(uri)
+           uriResult = URI("$scheme://$rawAuthority$path?$signedCanonicalQueryString")
        } catch (e: URISyntaxException) {
            Log.e(TAG, e.message ?: "")
        }
        return uriResult
    }

More information about java.net.URI encode https://stackoverflow.com/questions/4858108/url-to-uri-encoding-changes-a-3d-to-253d