Carga de un archivo a través de SSL con Client Side Certificate y HttpsURLConnection de Android

Estoy intentando subir un archivo a un servicio web que está protegido con SSL y requiere un certificado del lado del cliente (firmado por una CA interna). La comunicación con el servicio web funciona bien (descargar archivos, consultar, ejecutar comandos y realizar todo tipo de POST funciona bien como se esperaba), excepto para cargar archivos .

Cuando subo archivos obtengo una SSLException (javax.net.ssl.SSLException) que dice "Error de escritura: ssl = 0x5fe209c0: Error de E / S durante la llamada al sistema, Conexión restablecida por peer".

He creado un servidor duplicado y he eliminado los requisitos SSL y Client-Certificate, y he intentado cargar sobre HTTP 'vainilla', y funciona perfectamente.

He intentado usar setFixedLengthStreamingMode (int) y setChunkedStreamingMode (int) sin éxito. Al usarlos, la excepción se lanza desde el método de write , y cuando no se utiliza ninguno de ellos, la misma excepción se lanza desde la llamada a getResponseCode() .

No pude encontrar nada sobre el error en EventVwr del servidor.

Nuestro otro cliente (cliente de iOS) puede subir archivos allí, así que debe ser algo que yo haga – pero no puedo averiguar qué.

No estoy seguro de cómo depurar este problema más.

Por favor ayuda.

Editar 1

Hemos hecho un montón de esfuerzos de depuración y hemos encontrado que:

  • Los archivos pequeños se cargan como se esperaba (44kb es el tamaño del archivo más grande que se cargó correctamente y se cargó en ~ 1200ms).
  • No se pudo cargar un archivo de 46 KB. El fallo tomó ~ 2 minutos (134120ms).

Editar 2

Después de lo que vas a leer en las observaciones, ahora tengo Fiddler para jugar bien (Gracias a esta pregunta ). Fiddler consiguió el archivo, pero no tuvo éxito en enviarlo. Las peticiones (primas) se parecen a:

 POST https://192.168.2.2/rest/transfer/strong/Upload/Full?Path=%5C20140807_113255_20.jpg&Root=2 HTTP/1.1 SessionToken: 1234 // We use this for session management FileMetadata: {"FileSize":"1315496","FileName":"GrumpyCat.jpg"} Connection: Keep-Alive User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.1.1; GT-N7100 Build/JRO03C) Host: 192.168.2.2 Accept-Encoding: gzip Content-Type: application/x-www-form-urlencoded Content-Length: 1315496 ;odiao;awriorijgoeijoeirj;oedfrvgerg... // The image 

La respuesta de Fiddler (también RAW) fue:

 HTTP/1.1 504 Fiddler - Send Failure Date: Wed, 20 Aug 2014 17:40:29 GMT Content-Type: text/html; charset=UTF-8 Connection: close Timestamp: 20:40:29.420 [Fiddler] ResendRequest() failed: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host. < An existing connection was forcibly closed by the remote host 

Además, hemos agregado el 'MessageLogging' de WCF y el 'Tracing' detallado. MessageLogging no muestra ninguna pista del mensaje (probablemente se cayó antes de convertirse en un mensaje), pero el rastro mostró esto: El rastro de WCF como se ve desde el SvcTraceViewer

Ahora, antes de decir "ahhh, este es un problema de servidor", tenga en cuenta que los archivos de 44kb tienen éxito en la carga, y nuestra aplicación iOS también es capaz de cargar archivos con éxito.

Esta es la pila de llamadas de la excepción que obtiene el cliente:

 E/RestClientUploader(3196): javax.net.ssl.SSLException: Write error: ssl=0x5d94b8b0: I/O error during system call, Connection reset by peer E/RestClientUploader(3196): at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_write(Native Method) E/RestClientUploader(3196): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:693) E/RestClientUploader(3196): at java.io.ByteArrayOutputStream.writeTo(ByteArrayOutputStream.java:231) E/RestClientUploader(3196): at libcore.net.http.ChunkedOutputStream.writeBufferedChunkToSocket(ChunkedOutputStream.java:129) E/RestClientUploader(3196): at libcore.net.http.ChunkedOutputStream.write(ChunkedOutputStream.java:77) E/RestClientUploader(3196): at java.io.DataOutputStream.write(DataOutputStream.java:98) E/RestClientUploader(3196): at com.varonis.datanywhere.communication.RestClientUploader.uploadFileToServer(RestClientUploader.java:151) E/RestClientUploader(3196): at com.varonis.datanywhere.communication.RestClientUploader.uploadFullFile(RestClientUploader.java:67) E/RestClientUploader(3196): at com.varonis.datanywhere.communication.services.FileUploadService.doUpload(FileUploadService.java:128) E/RestClientUploader(3196): at com.varonis.datanywhere.communication.services.FileUploadService.onHandleIntent(FileUploadService.java:98) E/RestClientUploader(3196): at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65) E/RestClientUploader(3196): at android.os.Handler.dispatchMessage(Handler.java:99) E/RestClientUploader(3196): at android.os.Looper.loop(Looper.java:137) E/RestClientUploader(3196): at android.os.HandlerThread.run(HandlerThread.java:60) 

No es una respuesta, más un trabajo alrededor – para su referencia.

Después de golpear nuestras cabezas alrededor de este problema, y ​​haciendo un montón de investigación, nos dimos por vencidos. Hemos abierto este problema con Google e implementado el siguiente trabajo:

Para cargar un archivo, la aplicación obtiene primero un Token de carga a través de un punto final que requiere el certificado de cliente y, a continuación, utiliza este token para cargarlo en un punto final que no requiere el certificado de cliente (pero aún sobre SSL (Https) ).

Sí, es un pequeño incumplimiento de la seguridad, pero tuvimos que hacerlo. Lo hemos protegido todo lo que pudimos …

Prometo actualizar cuando el boleto de Google será actualizado (y esperanzadamente resuelto).

HTH!

Es un poco tarde (ya que ya implementó una solución), pero esto debería resolver el problema: https://stackoverflow.com/a/9224892/1619545

Estamos experimentando el mismo problema, establecer el cliente cert negociar bandera para habilitado parece ser lo único que ayuda hat. Echa un vistazo aquí para saber cómo cambiar la bandera en el cert vinculante:

http://help.sap.com/saphelp_smp305svr/helpdata/es/6f/f0a9b6e1c743d48d1e57235d297c1c/content.htm

  • Aceptar certificados SSL autofirmados-> donde configurar TrustManager predeterminado
  • Cuándo instalar keystore & cuándo instalar sólo el certificado envuelto en keystore
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.