@@ -9,9 +9,14 @@ import androidx.annotation.IdRes
9
9
import androidx.appcompat.app.AppCompatActivity
10
10
import androidx.core.content.ContextCompat
11
11
import com.android.volley.RequestQueue
12
- import com.android.volley.toolbox.*
12
+ import com.android.volley.toolbox.BasicNetwork
13
+ import com.android.volley.toolbox.HurlStack
14
+ import com.android.volley.toolbox.NoCache
15
+ import com.android.volley.toolbox.StringRequest
13
16
import com.datatheorem.android.trustkit.TrustKit
14
- import kotlinx.coroutines.*
17
+ import kotlinx.coroutines.Dispatchers
18
+ import kotlinx.coroutines.GlobalScope
19
+ import kotlinx.coroutines.launch
15
20
import okhttp3.CertificatePinner
16
21
import okhttp3.OkHttpClient
17
22
import okhttp3.Request
@@ -218,9 +223,50 @@ class MainActivity : AppCompatActivity() {
218
223
}
219
224
}
220
225
221
- fun sendManuallyCustomPinned (view : View ) {
226
+ // Manually pinned by building an SSLContext that trusts only the correct certificate, and then
227
+ // connecting with the native HttpsUrlConnection API:
228
+ fun sendCustomContextPinned (view : View ) {
222
229
GlobalScope .launch(Dispatchers .IO ) {
223
- onStart(R .id.manually_pinned)
230
+ onStart(R .id.custom_context_pinned)
231
+
232
+ val cf = CertificateFactory .getInstance(" X.509" )
233
+ val caStream = BufferedInputStream (resources.openRawResource(R .raw.lets_encrypt_isrg_root))
234
+ val caCertificate = cf.generateCertificate(caStream)
235
+
236
+ val keyStore = KeyStore .getInstance(KeyStore .getDefaultType())
237
+ keyStore.load(null )
238
+ keyStore.setCertificateEntry(" ca" , caCertificate)
239
+
240
+ val trustManagerFactory = TrustManagerFactory
241
+ .getInstance(TrustManagerFactory .getDefaultAlgorithm())
242
+ trustManagerFactory.init (keyStore)
243
+
244
+ try {
245
+ val context = SSLContext .getInstance(" TLS" )
246
+ context.init (null , trustManagerFactory.trustManagers, null )
247
+
248
+ val mURL = URL (" https://sha256.badssl.com" )
249
+ with (mURL.openConnection() as HttpsURLConnection ) {
250
+ this .sslSocketFactory = context.socketFactory
251
+
252
+ println (" URL: ${this .url} " )
253
+ println (" Response Code: ${this .responseCode} " )
254
+ }
255
+
256
+ onSuccess(R .id.custom_context_pinned)
257
+ } catch (e: Throwable ) {
258
+ println (e)
259
+ onError(R .id.custom_context_pinned, e.toString())
260
+ }
261
+ }
262
+ }
263
+
264
+ // Manually pinned at the lowest level: creating a raw TLS connection, disabling all checks,
265
+ // and then directly analysing the certificate that's received after connection, before doing
266
+ // HTTP by just writing & reading raw strings. Not a good idea, but the hardest to unpin!
267
+ fun sendCustomRawSocketPinned (view : View ) {
268
+ GlobalScope .launch(Dispatchers .IO ) {
269
+ onStart(R .id.custom_raw_socket_pinned)
224
270
try {
225
271
// Disable trust manager checks - we'll check the certificate manually ourselves later
226
272
val trustManager = arrayOf<TrustManager >(object : X509TrustManager {
@@ -257,10 +303,10 @@ class MainActivity : AppCompatActivity() {
257
303
println (" Response was: $responseLine " )
258
304
socket.close()
259
305
260
- onSuccess(R .id.manually_pinned )
306
+ onSuccess(R .id.custom_raw_socket_pinned )
261
307
} catch (e: Throwable ) {
262
308
println (e)
263
- onError(R .id.manually_pinned , e.toString())
309
+ onError(R .id.custom_raw_socket_pinned , e.toString())
264
310
}
265
311
}
266
312
}
0 commit comments