The following sample code demonstrates how to connect to a server that delivers a certificate with a wrong or invalid hostname using SSLSocket which inherently doesn't perform any hostname validation checks.
However, the code implements a custom HostnameVerifier that performs hostname verification, thus blocking the connection to the server with the wrong hostname.
packageorg.owasp.mastestappimportandroid.content.Contextimportjava.io.BufferedReaderimportjava.io.InputStreamReaderimportjavax.net.ssl.HttpsURLConnectionimportjavax.net.ssl.SSLExceptionimportjavax.net.ssl.SSLSocketimportjavax.net.ssl.SSLSocketFactoryclassMastgTest(privatevalcontext:Context){funmastgTest():String{varsocket:SSLSocket? =nullreturntry{// Use the default SSLSocketFactoryvalsslSocketFactory=SSLSocketFactory.getDefault()asSSLSocketFactory// Connect to the server using SSLSocketvalhost="wrong.host.badssl.com"valport=443socket=sslSocketFactory.createSocket(host,port)asSSLSocket// Start the handshakesocket.startHandshake()valhostnameVerifier=HttpsURLConnection.getDefaultHostnameVerifier()valsession=socket.sessionif(!hostnameVerifier.verify(host,session)){throwSSLException("Hostname verification failed for host: $host")}// Send an HTTP GET requestvalrequest="GET / HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n\r\n"valout=socket.outputStreamout.write(request.toByteArray())out.flush()// Read the response (this will read until the server closes)valreader=BufferedReader(InputStreamReader(socket.inputStream))valresponse=reader.readText()"Connection Successful: ${response.substring(0,minOf(200,response.length))}"}catch(e:Exception){e.printStackTrace()"Connection Failed: ${e::class.simpleName} - ${e.message}"}finally{// Clean up: close the socketsocket?.let{try{it.close()}catch(_:Exception){}}}}}
packageorg.owasp.mastestapp;importandroid.content.Context;importandroidx.compose.runtime.ComposerKt;importjava.io.BufferedReader;importjava.io.InputStreamReader;importjava.io.OutputStream;importjava.net.Socket;importjavax.net.SocketFactory;importjavax.net.ssl.HostnameVerifier;importjavax.net.ssl.HttpsURLConnection;importjavax.net.ssl.SSLException;importjavax.net.ssl.SSLSession;importjavax.net.ssl.SSLSocket;importjavax.net.ssl.SSLSocketFactory;importkotlin.Metadata;importkotlin.io.TextStreamsKt;importkotlin.jvm.internal.Intrinsics;importkotlin.jvm.internal.Reflection;importkotlin.text.Charsets;/* compiled from: MastgTest.kt */@Metadata(d1={"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0000\b\u0007\u0018\u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0002\u0010\u0004J\u0006\u0010\u0005\u001a\u00020\u0006R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\u0007"},d2={"Lorg/owasp/mastestapp/MastgTest;","","context","Landroid/content/Context;","(Landroid/content/Context;)V","mastgTest","","app_debug"},k=1,mv={1,9,0},xi=48)/* loaded from: classes4.dex */publicfinalclassMastgTest{publicstaticfinalint$stable=8;privatefinalContextcontext;publicMastgTest(Contextcontext){Intrinsics.checkNotNullParameter(context,"context");this.context=context;}publicfinalStringmastgTest(){Stringstr;SSLSocketsocket;HostnameVerifierhostnameVerifier;SSLSessionsession;SSLSocketsocket2=null;try{try{SocketFactorysocketFactory=SSLSocketFactory.getDefault();Intrinsics.checkNotNull(socketFactory,"null cannot be cast to non-null type javax.net.ssl.SSLSocketFactory");SSLSocketFactorysslSocketFactory=(SSLSocketFactory)socketFactory;SocketcreateSocket=sslSocketFactory.createSocket("wrong.host.badssl.com",443);Intrinsics.checkNotNull(createSocket,"null cannot be cast to non-null type javax.net.ssl.SSLSocket");socket=(SSLSocket)createSocket;socket.startHandshake();hostnameVerifier=HttpsURLConnection.getDefaultHostnameVerifier();session=socket.getSession();}catch(Exceptione){e.printStackTrace();str="Connection Failed: "+Reflection.getOrCreateKotlinClass(e.getClass()).getSimpleName()+" - "+e.getMessage();if(0!=0){try{socket2.close();}catch(Exceptione2){}}}if(!hostnameVerifier.verify("wrong.host.badssl.com",session)){thrownewSSLException("Hostname verification failed for host: wrong.host.badssl.com");}Stringrequest="GET / HTTP/1.1\r\nHost: wrong.host.badssl.com\r\nConnection: close\r\n\r\n";OutputStreamout=socket.getOutputStream();byte[]bytes=request.getBytes(Charsets.UTF_8);Intrinsics.checkNotNullExpressionValue(bytes,"this as java.lang.String).getBytes(charset)");out.write(bytes);out.flush();BufferedReaderreader=newBufferedReader(newInputStreamReader(socket.getInputStream()));Stringresponse=TextStreamsKt.readText(reader);StringBuilderappend=newStringBuilder().append("Connection Successful: ");Stringsubstring=response.substring(0,Math.min(ComposerKt.invocationKey,response.length()));Intrinsics.checkNotNullExpressionValue(substring,"this as java.lang.String…ing(startIndex, endIndex)");str=append.append(substring).toString();try{socket.close();}catch(Exceptione3){}returnstr;}catch(Throwableth){if(0!=0){try{socket2.close();}catch(Exceptione4){}}throwth;}}}
rules:-id:mastg-android-ssl-socket-hostnameverifierseverity:WARNINGlanguages:-javametadata:summary:ThisrulesscansfortheusageofSSLSocketAPIwithaHostnameVerifier.message:"Detected usage of SSLSocket API with or without a HostnameVerifier"match:any:-pattern:SSLSocketFactory.getDefault()-pattern:(SSLSocketFactory)$_-pattern:$SF.createSocket(...)-pattern:HttpsURLConnection.getDefaultHostnameVerifier()-pattern:$HNV.verify($_,$_)