Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uploading a file over SSL with Client Side Certificate and Android's HttpsURLConnection

Tags:

I'm trying to upload a file to a web-service that is protected with SSL and requires a client-side certificate (signed by an in-house CA). The communication to the web-service works well (Downloading files, Querying, running commands and performing all sorts of POSTs works well as expected), except for uploading files.

When uploading files I get an SSLException (javax.net.ssl.SSLException) that says "Write error: ssl=0x5fe209c0: I/O error during system call, Connection reset by peer".

I have created a duplicate server and removed the SSL and Client-Certificate requirements, and tried to upload over 'vanilla' HTTP, and it works perfectly.

I've tried using setFixedLengthStreamingMode(int) and setChunkedStreamingMode(int) without success. When using them, the exception is thrown from the write method, and when not using any of them, the same exception is thrown from the call to getResponseCode().

I couldn't find anything about the error in the server's EventVwr.

Our other client (iOS client) is able to upload files there, so it must be something that I do - but I can't figure out what.

I'm not sure how to debug this issue further.

Please help.

Edit 1

We've done a lot of debugging efforts, and found that:

  • Small files are uploaded as expected (44kb is the size of the largest file that was uploaded successfully, and it uploaded in ~1200ms).
  • An 46kb file failed to upload. The failure took ~2 minutes (134120ms).

Edit 2

After what you'll read in the remarks, now I got Fiddler to play nice (Thanks to this question). Fiddler got the file, but did not succeed in sending it. The requests (raw) looks like:

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 

Fiddler's response (also RAW) was:

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                                                                                                                                                                                                                                                                                                               

Also, We've added WCF's 'MessageLogging' and verbose 'Tracing'. MessageLogging don't show any hint of the message (probably dropped before turning into a message), but the trace showed this: The WCF Trace as seen from the SvcTraceViewer

Now, before you say "ahhh, this is a server problem", keep in mind that 44kb files succeed in uploading, and our iOS app also is able to upload files successfully.

This is the call stack from the exception that the client gets:

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) 
like image 312
Felix Avatar asked Aug 17 '14 15:08

Felix


People also ask

How do I use client certificates in a client Java application?

Client Java Implementation First, we create an SSLSocket that establishes a connection with the server. In the background, the socket will set up the TLS connection establishment handshake. As part of this handshake, the client will verify the server's certificate and check that it's in the client truststore.

What is SSL certificate in Android?

SSL stands for Secure Sockets Layer. SSL is the standard security technology for establishing an encrypted link between a client and a server. This link ensures that all data passed between the web server and browser remain private.

What is SSL in Android architecture?

The Secure Sockets Layer (SSL)—now technically known as Transport Layer Security (TLS)—is a common building block for encrypted communications between clients and servers. Using TLS incorrectly might let malicious entities intercept an app's data over the network.

What is self signed certificate in Android?

The certificates allow the Android system to identify the author of an application and establish trust relationships between developers and their applications. The certificates are not used to control which applications the user can and cannot install.


2 Answers

Not an answer, more a work-around, for your reference.

After bashing our heads around this issue, and doing a lot of research, we gave up. We've opened this issue with Google, and implemented the following work around:

In order to upload a file, the app first gets an Upload Token via an endpoint that requires the client-certificate, and afterwards uses this token to upload to an endpoint that doesn't require the client certificate (but still over SSL (Https)).

Yes, it's a minor breach of security, but we had to do it. We've protected it as much as we could.

I promise to update when the Google's ticket will be updated (and hopefully resolved).

like image 142
Felix Avatar answered Nov 03 '22 22:11

Felix


It's a bit late (as you already implemented a workaround) but this should solve the problem: https://stackoverflow.com/a/9224892/1619545

We're experiencing the same issue, setting the client cert negotiate flag to enabled seems to be the only thing hat helps. Have a look here for a way how to change the flag at the cert binding:

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

like image 25
AndyB Avatar answered Nov 03 '22 23:11

AndyB