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
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.
[~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?
On Android, if the certificates don't match, we throw this error:
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".
[~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.
Sample code to detect 'Man in the middle' attack on Android:
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
iOS has been updated to work like Android. onerror(e) will be called * e.error: will have the same message
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 PMCreated Doc ticket: TIDOC-2115
Verified the fix using appcelerator.https v1.1.2 & SDK 4.0.0.v20150313181810. We see exception thrown on IOS:
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