Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-18129] Https Module does not throw exception on fail as expected

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2015-02-06T17:25:17.000+0000
Affected Version/sn/a
Fix Version/sRelease 4.0.0
ComponentsAndroid, iOS
LabelssupportTeam
ReporterMarco Cota
AssigneeVishal Duggal
Created2014-11-03T16:10:46.000+0000
Updated2015-03-19T00:46:44.000+0000

Description

Issue

According to our documentation when the HTTPClient send() is called to do an https request and the authentication fails, a security exception will be thrown but instead customer receives a WARNING log on iOS and an ERROR log in Android to finish the call with the onError callback being fired. This is causing than when customer tries to catch the exception is not possible.
After the securityManager property is set, call the HTTPClient's open() and send() methods to initiate the HTTPS request.

httpClient.open("GET", "https://yourorg.com");
httpClient.send();

If the authentication fails, a security exception is thrown.

Log

iOS
[INFO]  httpClient Created.
[WARN]  Potential "Man-in-the-Middle" attack detected since host www.appcelerator.com does not hold the private key corresponding to the public key PublicKey: <SecKeyRef algorithm id: 1, key type: RSAPublicKey, version: 3, block size: 2048 bits, exponent: {hex: 10001, decimal: 65537}, modulus: C15236913979042DF078DF5B73AF463A636F98CE32A2AABAC378180566A87C382BB3A82A6808D4103D626A37CA4FBF8ABEA5939DD6C9874A8D318593F5481F59756E76817CBD38B73A5C703438BB9A824FD054B168ED3C9E5CD0445F744ED2A4EAA6327A94813A98C941BD60F3B19C5DC8CDFB34DE9293C53D41A234B4499A4F19C6AF193084F61C6636D7E89AEA86110231E6EE03F4C853841B0FB46122E6D73E7EF08D058665C7297B1A329F16F0EEB856E7614EB16B23CB4B6BBC5B567685F02638B52ECEBC71B06A1503776C0945A75E3227F71FE2956FC48533A6529066C840433A6705E94523843D10C45A8BC9CD58FCA6A6AABD79F2FFFEE6CB254AB9, addr: 0x79ba6600>.
[INFO]  onerror()
[INFO]  {"type":"error","source":{"method":"GET","securityManager":{},"timeout":25000,"url":"https://www.appcelerator.com"},"code":-1012,"error":"The operation couldn’t be completed. (NSURLErrorDomain error -1012.)","success":false}
Android
[INFO]  httpClient Created.
[DEBUG] dalvikvm: GC_CONCURRENT freed 231K, 2% free 16219K/16524K, paused 4ms+0ms, total 8ms
[ERROR] TiHttpClient: (TiHttpClient-1) [3000,3000] HTTP Error (javax.net.ssl.SSLHandshakeException): Leaf certificate could not be verified with provided public key
[ERROR] TiHttpClient: javax.net.ssl.SSLHandshakeException: Leaf certificate could not be verified with provided public key
[ERROR] TiHttpClient: 	at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:409)
[ERROR] TiHttpClient: 	at com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream.<init>(OpenSSLSocketImpl.java:661)
[ERROR] TiHttpClient: 	at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:632)
[ERROR] TiHttpClient: 	at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:70)
[ERROR] TiHttpClient: 	at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83)
[ERROR] TiHttpClient: 	at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170)
[ERROR] TiHttpClient: 	at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106)
[ERROR] TiHttpClient: 	at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129)
[ERROR] TiHttpClient: 	at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:172)
[ERROR] TiHttpClient: 	at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
[ERROR] TiHttpClient: 	at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
[ERROR] TiHttpClient: 	at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
[ERROR] TiHttpClient: 	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
[ERROR] TiHttpClient: 	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:653)
[ERROR] TiHttpClient: 	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:637)
[ERROR] TiHttpClient: 	at ti.modules.titanium.network.TiHTTPClient$ClientRunnable.run(TiHTTPClient.java:1328)
[ERROR] TiHttpClient: 	at java.lang.Thread.run(Thread.java:841)
[ERROR] TiHttpClient: Caused by: java.security.cert.CertificateException: Leaf certificate could not be verified with provided public key
[ERROR] TiHttpClient: 	at appcelerator.https.PinningTrustManager.checkServerTrusted(PinningTrustManager.java:84)
[ERROR] TiHttpClient: 	at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:613)
[ERROR] TiHttpClient: 	at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
[ERROR] TiHttpClient: 	at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
[ERROR] TiHttpClient: 	... 16 more
[INFO]  onerror()
[INFO]  {"code":-1,"source":{"autoRedirect":true,"status":0,"responseData":null,"connected":false,"readyState":1,"allResponseHeaders":"","responseText":"","username":null,"timeout":25000,"statusText":null,"autoEncodeUrl":true,"apiName":"Ti.Network.HTTPClient","validatesSecureCertificate":false,"location":"https://www.appcelerator.com","domain":null,"connectionType":"GET","responseXML":null,"bubbleParent":true,"password":null,"securityManager":{"bubbleParent":true,"apiName":"appcelerator.Https.PinningSecurityManager"},"_events":{"disposehandle":{}}},"error":"Leaf certificate could not be verified with provided public key","success":false}

Test code

var win = Ti.UI.createWindow();
var but = Ti.UI.createButton({
	title:"click"
});

but.addEventListener('click',doClick);
var https = require("appcelerator.https");

function doClick(e) {
   
   	var securityManager = https.createX509CertificatePinningSecurityManager([{
		url: 'https://www.appcelerator.com',
		serverCertificate: 'google.com.der'
	}]);

   var httpClient = Ti.Network.createHTTPClient({
		timeout : 25000,
		securityManager: securityManager
	});
	
	httpClient.onload = function(e) {
		Ti.API.info('onload()');
	};
	httpClient.onerror = function(e) {
		Ti.API.info('onerror()');
	};
	
	Ti.API.info("httpClient Created.");
	
	try {
		httpClient.open('GET', 'https://www.appcelerator.com');	
		httpClient.send();
	} catch (exception) {
		Ti.API.info('SecurityException occurred');
	}
}

win.add(but);
win.open();

Steps to repro

1. run test case ( demo.zip) 2. click on the button Expected Result A security exception is thrown and handled by the catch code Actual Result No exception is thrown

Attachments

FileDateSize
demo.zip2014-11-03T16:10:46.000+00005891463

Comments

  1. Ingo Muschenetz 2014-11-03

    According to the code, they should use the OnError event instead as an exception is not being thrown. However, we should investigate why the error is no longer thrown.
  2. Ingo Muschenetz 2014-12-04

    [~hpham] I believe there are two issues. One is that the behavior seemed to change, and [~rtlechuga] indicates that onError doesn't work for them. The second (at least) is that we should return the same on both platforms. Why a warning on iOS?
  3. Hieu Pham 2014-12-04

    On Android, if the certificates don't match, we throw this error:
         throw new CertificateException("Leaf certificate could not be verified with provided public key");
       
    which is the same one you're seeing in the log. This error message is also passed into the onError callback via 'error' property. So in order to detect 'man in the middle attack' on Android, simply compare e.error from onError with the "Leaf certificate could not be verified with provided public key".
  4. Neeraj Gupta 2014-12-05

    [~hpham] Can you please provide a simple code example with onError that support can pass to Comerica for verification? There seems to be a disconnect here. We should also make iOS and Android behaviors consistent.
  5. Hieu Pham 2014-12-05

    Sample code to detect 'Man in the middle' attack on Android:
       httpClient.onerror = function(e) {
       		Ti.API.info('onerror()');
       		var index = e.error.indexOf("Leaf certificate could not be verified with provided public key");
       		if (index > -1) {
       			//man in middle detected.
       		}
       };
       
  6. Pedro Enrique 2015-01-09

    Sometimes Apple is not very clear with their error messages. If you're doing an http request and for some reason it fails, you'll get a message in the "onerror" callback. {quote} The operation couldn’t be completed. (NSURLErrorDomain error _error_code_) {quote} The error code is what we really care about. I have not found specific documentation, but all my research points me to one conclusion, error code -1012 means that something was wrong with the an SSL certificate.

    The immediate workaround

       httpClient.onerror = function(e) {
           if(e.code == -1012) {
               // man-in-the-middle - do something here
           }
           Ti.API.info('onerror()');
       };
       
  7. Jon Alter 2015-02-06

    iOS has been updated to work like Android. onerror(e) will be called * e.error: will have the same message
       // iOS
       httpClient.onerror = function(e) {
       	Ti.API.info('onerror(): ' + JSON.stringify(e));
       };
       // [INFO]  onerror(): {"type":"error","source":{"method":"GET","securityManager":{},"timeout":25000,"url":"https://www.appcelerator.com"},"code":-1,"error":"Leaf certificate could not be verified with provided public key","success":false}
       

    This fix requires:

    * [appcelerator.https v1.1.2](https://github.com/appcelerator-modules/appcelerator.https/releases/tag/1.1.2) or newer * titanium_mobile build newer than (but not including) "mobilesdk-4.0.0.v20150205163226-osx.zip" from THU FEB 05, 2015 4:32:26 PM
  8. Jon Alter 2015-02-06

    Created Doc ticket: TIDOC-2115
  9. Lokesh Choudhary 2015-03-19

    Verified the fix using appcelerator.https v1.1.2 & SDK 4.0.0.v20150313181810. We see exception thrown on IOS:
       [INFO] :   onerror(): {"success":false,"code":-1,"source":{"url":"https://www.appcelerator.com","method":"GET","timeout":25000,"securityManager":{}},"type":"error","error":"Leaf certificate could not be verified with provided public key"}
       
    Closing. Environment: Appc Studio : 3.5.1.201412091616 Ti SDK : 4.0.0.v20150313181810 CLI : 3.4.2 Alloy : 1.5.1 MAC Yosemite : 10.10.2 Iphone 6 - IOS 8.2

JSON Source