ProGuard causa error de handshake SSL en Android

Mi aplicación se comporta bien sin ofuscación (específicamente WITH -dontobfuscate habilitado en ProGuard), pero tan pronto como habilitar ofuscación, las consultas SSL fallan con tal error:

javax.net.ssl.SSLHandshakeException: Handshake failed at com.google.android.gms.org.conscrypt.OpenSSLSocketImpl.startHandshake(:com.google.android.gms:418) at com.android.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:212) at com.android.okhttp.Connection.connect(Connection.java:1322) at com.android.okhttp.Connection.connectAndSetOwner(Connection.java:1410) at com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:131) at com.android.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:484) at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:465) at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:371) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:476) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:118) at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:89) at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:25) 

Cualquier idea que la clase podría estar causando?

Configuración de ProGuard:

 -dontoptimize #-dontobfuscate # Preverification is irrelevant for the dex compiler and the Dalvik VM. -dontpreverify -ignorewarnings #-printusage "usage.txt" # usunięte z powodu crashlytics #-printmapping "out.map" # Reduce the size of the output some more. #-repackageclasses '' #-allowaccessmodification # Switch off some optimizations that trip older versions of the Dalvik VM. #-optimizations !code/simplification/arithmetic # Keep a fixed source file attribute and all line number tables to get line # numbers in the stack traces. # You can comment this out if you're not interested in stack traces. -renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable # RemoteViews might need annotations. -keepattributes *Annotation* # Preserve all fundamental application classes. -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.preference.Preference # Preserve all View implementations, their special context constructors, and # their setters. -keep public class * extends android.view.View { public <init>(android.content.Context); public <init>(android.content.Context, android.util.AttributeSet); public <init>(android.content.Context, android.util.AttributeSet, int); public void set*(...); } # Preserve all classes that have special context constructors, and the # constructors themselves. -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet); } # Preserve all classes that have special context constructors, and the # constructors themselves. -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet, int); } -keepclassmembers class * extends android.content.Context { public void *(android.view.View); public void *(android.view.MenuItem); } # Preserve the special fields of all Parcelable implementations. -keepclassmembers class * implements android.os.Parcelable { static android.os.Parcelable$Creator CREATOR; } # Preserve static fields of inner classes of R classes that might be accessed # through introspection. -keepclassmembers class **.R$* { public static <fields>; } # Preserve the required interface from the License Verification Library # (but don't nag the developer if the library is not used at all). -keep public interface com.android.vending.licensing.ILicensingService -dontnote com.android.vending.licensing.ILicensingService # The Android Compatibility library references some classes that may not be # present in all versions of the API, but we know that's ok. -dontwarn android.support.** # Preserve all native method names and the names of their classes. -keepclasseswithmembernames class * { native <methods>; } # Preserve the special static methods that are required in all enumeration # classes. -keepclassmembers class * extends java.lang.Enum { public static **[] values(); public static ** valueOf(java.lang.String); } # Explicitly preserve all serialization members. The Serializable interface # is only a marker interface, so it wouldn't save them. # You can comment this out if your application doesn't use serialization. # If your code contains serializable classes that have to be backward # compatible, please refer to the manual. -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } -keep class * implements org.xml.sax.EntityResolver -keepclassmembers class * { ** MODULE$; } #################################################################################################### # moje #################################################################################################### # -keep public class mypackage.MyClass # -keep public interface mypackage.MyInterface # -keep public class * implements mypackage.MyInterface # bo animatory -keepclassmembers class pl.qus.** { public void set*(...); public *** get*(); } -keep class pl.qus.xenoamp.fragment.** { *; } # chyba konieczne dla adapterów używanych w ciele withView<>() -keep class pl.qus.xenoamp.adapter.** { *; } -keep class pl.qus.clients.model.** { *; } # Crashlytics #-keep class com.crashlytics.** { *; } #-keep class com.crashlytics.android.** -keep public class * extends java.lang.Exception # Event Bus -keepclassmembers class pl.qus.** { public void onEvent*(**); } # audiotagger -keep class org.jaudiotagger.** { *; } #################################################################################################### # nie-moje #################################################################################################### # gson-xml -keep class stanfy.** { *; } # jcifs -keep class jcifs.** { *; } # cling -keep class org.fourthline.** { *; } -keepattributes InnerClasses #-keep class nurik.wizard.** { *; } # textSurface -keep class su.levenetc.android.textsurface.** { *; } # Gson uses generic type information stored in a class file when working with fields. Proguard # removes such information by default, so configure it to keep all of it. # bez tego kotlinowe lambdy będą się jebać! -keepattributes Signature # Gson specific classes -keep class sun.misc.Unsafe { *; } # Green dao -keepclassmembers class * extends de.greenrobot.dao.AbstractDao { public static java.lang.String TABLENAME; } -keep class **$Properties # play services -keep public class com.google.android.gms.* { public *; } -dontwarn com.google.android.gms.** # spotify -keep class com.spotify.** { *; } # jsoup -keep class org.jsoup.** { *; } -keep class tv.danmaku.ijk.** { *; } 

La petición se hace así:

  val respons = Rest.getResponse( method = "GET", protocol = scheme, host = host, path = "/rest/ping.view", query = prepareStdArgs(), port = port ) 

Con dicho código:

 fun getResponse(method: String = "GET", protocol: String = "https", host: String, path: String, query: Map<String, String> = hashMapOf<String, String>(), headery: MutableMap<String, String> = hashMapOf<String, String>(), allowRedirects: Boolean = false, postContents: String = "", useCache: Boolean = true, wait: Long = 0, port: Int = -1): RestResponse { if (!useCache) { Thread.sleep(wait) } val connection = getConnection(method, protocol, host, path, headery, query, port) as HttpURLConnection if (!allowRedirects) connection.instanceFollowRedirects = false return connection.obtainRestResponse(postContents, useCache).apply { connection.disconnect() } } private fun getConnection(method: String, protocol: String, host: String, path: String, headery: MutableMap<String, String>, query: Map<String, String>, port : Int = -1): URLConnection { if(protocol=="https") { val sc = SSLContext.getInstance("TLS") // bylo: SSL sc.init(null, XenoHttpClient.trustAllCerts, java.security.SecureRandom()) HttpsURLConnection.setDefaultSSLSocketFactory(sc.socketFactory) HttpsURLConnection.setDefaultHostnameVerifier { s, sslSession -> true } } var connection = buildUrl(protocol, host, path, query, port).openConnection() as HttpURLConnection connection.requestMethod = method if (!headery.containsKey("User-Agent")) headery.put("User-Agent", "curl/7.22.0 (i686-pc-linux-gnu) libcurl/7.21.3 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.23") connection.applyHeaders(headery) connection.useCaches = false return connection } private fun HttpURLConnection.obtainRestResponse(postContents: String = "", useCache: Boolean = true): RestResponse { if (postContents.isNotBlank()) { this.doOutput = true Logger.d("POST contents:$postContents") DataOutputStream(this.outputStream).let { it.writeBytes(postContents) it.flush() it.close() } } this.connect() if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_MOVED_TEMP) { val kesz = XenoFile(XenoAmp.cacheDir(), XenoUtility.md5(this.url.toString())) var cachingReq = false var istream = if (this.requestMethod.toUpperCase() != "GET") { // nie keszujemy put/delete! inputStream } else if (useCache && kesz.exists()) { // już go mamy, więc z niego czytamy Logger.d("Query cached locally:" + this.url.toString()) XenoFileInputStream(kesz) } else { // nie mamy w keszu cachingReq = useCache inputStream } val tekst = XenoFile.streamToText(istream) if (cachingReq) { XenoFile.cacheText(this.url.toString(), tekst) } return RestResponse(responseCode, headersToMap(this.headerFields), tekst) } else { if(errorStream!=null) { val tekst = try { XenoFile.streamToText(errorStream) } catch (x: Exception) { Logger.e(x, "Problem") "REST Error: Bad status: $responseCode" } Logger.d("Error stream:$tekst") throw IllegalStateException(tekst) } else { Logger.d("Problem obtaining response for:${this.url} --> $responseCode,$responseMessage") throw IllegalStateException(responseMessage) } } } fun buildUrl(protocol: String, host: String, path: String, query: Map<String, String>, port : Int = -1) = if(port!=-1) URL(protocol, host, port, path + query.toQueryString()) else URL(protocol, host, path + query.toQueryString()) 

Por el aspecto de que podría ser okhttp. ¿Has probado a agregar las reglas de okhttp proguard?

 -dontwarn com.squareup.okhttp3.** -keep class com.squareup.okhttp3.* { *;} -dontwarn okio. 

Dependiendo de la versión okhttp puede que tenga que perder el 3 en okhttp3

  • Deshabilitar la comprobación de certificados SSL en la biblioteca de actualización
  • Vimeo error de SSL con Retrofit en Android
  • Protocolos SSL / TLS y suites de cifrado con AndroidHttpClient
  • OkHttp certificado de confianza
  • Descifrado SSL de la aplicación de Android
  • La conexión de twitter falló
  • El uso de la dirección IP para el nombre común en el certificado del servidor no funciona en Android?
  • Certificado SSL para los servicios web REST (utilizados por Android)?
  • Conexión de Https con conexión cerrada por peer en Android 6.0
  • Javax.net.ssl.SSLPeerUnverifiedException: Ningún certificado de compañero mientras estoy trabajando con google place api en android
  • ¿Por qué android obtiene el certificado ssl incorrecto? (Dos dominios, un servidor)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.