{ "id": "139002", "key": "TIMOB-18129", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [ { "id": "16593", "description": "Release 4.0.0", "name": "Release 4.0.0", "archived": false, "released": true, "releaseDate": "2015-05-21" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2015-02-06T17:25:17.000+0000", "created": "2014-11-03T16:10:46.000+0000", "priority": { "name": "High", "id": "2" }, "labels": [ "supportTeam" ], "versions": [], "issuelinks": [ { "id": "45772", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "144358", "key": "TIDOC-2115", "fields": { "summary": "Update documentation for Https Module", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "Medium", "id": "3" }, "issuetype": { "id": "7", "description": "gh.issue.story.desc", "name": "Story", "subtask": false } } } } ], "assignee": { "name": "vduggal", "key": "vduggal", "displayName": "Vishal Duggal", "active": false, "timeZone": "America/Los_Angeles" }, "updated": "2015-03-19T00:46:44.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10202", "name": "Android", "description": "Android Platform" }, { "id": "10206", "name": "iOS", "description": "iOS Platform" } ], "description": "h3. Issue\r\n\r\nAccording 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.\r\n\r\nThis is causing than when customer tries to catch the exception is not possible.\r\n\r\n{code}\r\nAfter the securityManager property is set, call the HTTPClient's open() and send() methods to initiate the HTTPS request.\r\n\r\nhttpClient.open(\"GET\", \"https://yourorg.com\");\r\nhttpClient.send();\r\n\r\nIf the authentication fails, a security exception is thrown.\r\n{code}\r\n\r\nh3. Log\r\n\r\niOS\r\n{code}\r\n[INFO] httpClient Created.\r\n[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: .\r\n[INFO] onerror()\r\n[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}\r\n{code}\r\n\r\nAndroid\r\n{code}\r\n[INFO] httpClient Created.\r\n[DEBUG] dalvikvm: GC_CONCURRENT freed 231K, 2% free 16219K/16524K, paused 4ms+0ms, total 8ms\r\n[ERROR] TiHttpClient: (TiHttpClient-1) [3000,3000] HTTP Error (javax.net.ssl.SSLHandshakeException): Leaf certificate could not be verified with provided public key\r\n[ERROR] TiHttpClient: javax.net.ssl.SSLHandshakeException: Leaf certificate could not be verified with provided public key\r\n[ERROR] TiHttpClient: \tat com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:409)\r\n[ERROR] TiHttpClient: \tat com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream.(OpenSSLSocketImpl.java:661)\r\n[ERROR] TiHttpClient: \tat com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:632)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.io.SocketInputBuffer.(SocketInputBuffer.java:70)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:172)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:653)\r\n[ERROR] TiHttpClient: \tat org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:637)\r\n[ERROR] TiHttpClient: \tat ti.modules.titanium.network.TiHTTPClient$ClientRunnable.run(TiHTTPClient.java:1328)\r\n[ERROR] TiHttpClient: \tat java.lang.Thread.run(Thread.java:841)\r\n[ERROR] TiHttpClient: Caused by: java.security.cert.CertificateException: Leaf certificate could not be verified with provided public key\r\n[ERROR] TiHttpClient: \tat appcelerator.https.PinningTrustManager.checkServerTrusted(PinningTrustManager.java:84)\r\n[ERROR] TiHttpClient: \tat com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:613)\r\n[ERROR] TiHttpClient: \tat com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)\r\n[ERROR] TiHttpClient: \tat com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)\r\n[ERROR] TiHttpClient: \t... 16 more\r\n[INFO] onerror()\r\n[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}\r\n{code}\r\n\r\nh3. Test code\r\n\r\n{code}\r\nvar win = Ti.UI.createWindow();\r\nvar but = Ti.UI.createButton({\r\n\ttitle:\"click\"\r\n});\r\n\r\nbut.addEventListener('click',doClick);\r\nvar https = require(\"appcelerator.https\");\r\n\r\nfunction doClick(e) {\r\n \r\n \tvar securityManager = https.createX509CertificatePinningSecurityManager([{\r\n\t\turl: 'https://www.appcelerator.com',\r\n\t\tserverCertificate: 'google.com.der'\r\n\t}]);\r\n\r\n var httpClient = Ti.Network.createHTTPClient({\r\n\t\ttimeout : 25000,\r\n\t\tsecurityManager: securityManager\r\n\t});\r\n\t\r\n\thttpClient.onload = function(e) {\r\n\t\tTi.API.info('onload()');\r\n\t};\r\n\thttpClient.onerror = function(e) {\r\n\t\tTi.API.info('onerror()');\r\n\t};\r\n\t\r\n\tTi.API.info(\"httpClient Created.\");\r\n\t\r\n\ttry {\r\n\t\thttpClient.open('GET', 'https://www.appcelerator.com');\t\r\n\t\thttpClient.send();\r\n\t} catch (exception) {\r\n\t\tTi.API.info('SecurityException occurred');\r\n\t}\r\n}\r\n\r\nwin.add(but);\r\nwin.open();\r\n{code}\r\n\r\nh3. Steps to repro\r\n\r\n1. run test case ( demo.zip)\r\n2. click on the button\r\n\r\nExpected Result\r\nA security exception is thrown and handled by the catch code\r\n\r\nActual Result\r\nNo exception is thrown", "attachment": [ { "id": "52297", "filename": "demo.zip", "author": { "name": "mcota", "key": "mcota", "displayName": "Marco Cota", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2014-11-03T16:10:46.000+0000", "size": 5891463, "mimeType": "application/zip" } ], "flagged": false, "summary": "Https Module does not throw exception on fail as expected", "creator": { "name": "mcota", "key": "mcota", "displayName": "Marco Cota", "active": false, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "mcota", "key": "mcota", "displayName": "Marco Cota", "active": false, "timeZone": "America/Los_Angeles" }, "environment": null, "closedSprints": [ { "id": 258, "state": "closed", "name": "2014 Sprint 24 SDK", "startDate": "2014-11-24T22:28:25.425Z", "endDate": "2014-12-06T01:00:00.000Z", "completeDate": "2014-12-08T17:21:15.171Z", "originBoardId": 114 }, { "id": 330, "state": "closed", "name": "2015 Sprint 03 SDK", "startDate": "2015-01-31T01:00:05.245Z", "endDate": "2015-02-14T01:00:00.000Z", "completeDate": "2015-02-16T21:01:51.914Z", "originBoardId": 114 } ], "comment": { "comments": [ { "id": "330575", "author": { "name": "ingo", "key": "ingo", "displayName": "Ingo Muschenetz", "active": true, "timeZone": "America/Los_Angeles" }, "body": "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.", "updateAuthor": { "name": "ingo", "key": "ingo", "displayName": "Ingo Muschenetz", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2014-11-03T18:23:54.000+0000", "updated": "2014-11-03T18:23:54.000+0000" }, { "id": "334858", "author": { "name": "ingo", "key": "ingo", "displayName": "Ingo Muschenetz", "active": true, "timeZone": "America/Los_Angeles" }, "body": "[~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?", "updateAuthor": { "name": "ingo", "key": "ingo", "displayName": "Ingo Muschenetz", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2014-12-04T17:30:21.000+0000", "updated": "2014-12-04T17:30:21.000+0000" }, { "id": "334917", "author": { "name": "hpham", "key": "hpham", "displayName": "Hieu Pham", "active": true, "timeZone": "America/Los_Angeles" }, "body": "On Android, if the certificates don't match, we throw this error:\r\n{code}\r\n throw new CertificateException(\"Leaf certificate could not be verified with provided public key\");\r\n{code}\r\nwhich 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\".", "updateAuthor": { "name": "hpham", "key": "hpham", "displayName": "Hieu Pham", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2014-12-04T22:13:52.000+0000", "updated": "2014-12-04T22:13:52.000+0000" }, { "id": "335004", "author": { "name": "ngupta", "key": "ngupta", "displayName": "Neeraj Gupta", "active": true, "timeZone": "America/Los_Angeles" }, "body": "[~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.", "updateAuthor": { "name": "ngupta", "key": "ngupta", "displayName": "Neeraj Gupta", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2014-12-05T07:26:25.000+0000", "updated": "2014-12-05T07:26:25.000+0000" }, { "id": "335135", "author": { "name": "hpham", "key": "hpham", "displayName": "Hieu Pham", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Sample code to detect 'Man in the middle' attack on Android:\r\n\r\n{code}\r\nhttpClient.onerror = function(e) {\r\n\t\tTi.API.info('onerror()');\r\n\t\tvar index = e.error.indexOf(\"Leaf certificate could not be verified with provided public key\");\r\n\t\tif (index > -1) {\r\n\t\t\t//man in middle detected.\r\n\t\t}\r\n};\r\n{code}", "updateAuthor": { "name": "ingo", "key": "ingo", "displayName": "Ingo Muschenetz", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2014-12-05T22:03:45.000+0000", "updated": "2015-01-05T18:12:08.000+0000" }, { "id": "338512", "author": { "name": "penrique", "key": "penrique", "displayName": "Pedro Enrique", "active": false, "timeZone": "America/Los_Angeles" }, "body": "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.\r\n{quote}\r\nThe operation couldn’t be completed. (NSURLErrorDomain error _error_code_)\r\n{quote}\r\nThe 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.\r\n\r\nh4. The immediate workaround\r\n{code}\r\nhttpClient.onerror = function(e) {\r\n if(e.code == -1012) {\r\n // man-in-the-middle - do something here\r\n }\r\n Ti.API.info('onerror()');\r\n};\r\n{code}", "updateAuthor": { "name": "penrique", "key": "penrique", "displayName": "Pedro Enrique", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2015-01-09T07:38:15.000+0000", "updated": "2015-01-09T07:39:05.000+0000" }, { "id": "342411", "author": { "name": "jalter", "key": "jalter", "displayName": "Jon Alter", "active": true, "timeZone": "America/Los_Angeles" }, "body": "iOS has been updated to work like Android.\r\n\r\nonerror(e) will be called\r\n* e.error: will have the same message\r\n\r\n{code}\r\n// iOS\r\nhttpClient.onerror = function(e) {\r\n\tTi.API.info('onerror(): ' + JSON.stringify(e));\r\n};\r\n// [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}\r\n{code}\r\n\r\nh5. This fix requires:\r\n* [appcelerator.https v1.1.2|https://github.com/appcelerator-modules/appcelerator.https/releases/tag/1.1.2] or newer\r\n* titanium_mobile build newer than (but not including) \"mobilesdk-4.0.0.v20150205163226-osx.zip\" from THU FEB 05, 2015 4:32:26 PM", "updateAuthor": { "name": "jalter", "key": "jalter", "displayName": "Jon Alter", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2015-02-06T17:00:52.000+0000", "updated": "2015-02-06T17:19:12.000+0000" }, { "id": "342416", "author": { "name": "jalter", "key": "jalter", "displayName": "Jon Alter", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Created Doc ticket: TIDOC-2115", "updateAuthor": { "name": "jalter", "key": "jalter", "displayName": "Jon Alter", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2015-02-06T17:24:47.000+0000", "updated": "2015-02-06T17:24:47.000+0000" }, { "id": "346488", "author": { "name": "lchoudhary", "key": "lchoudhary", "displayName": "Lokesh Choudhary", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Verified the fix using appcelerator.https v1.1.2 & SDK 4.0.0.v20150313181810. \r\nWe see exception thrown on IOS:\r\n{code}\r\n[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\"}\r\n{code}\r\n\r\nClosing.\r\n\r\nEnvironment:\r\nAppc Studio : 3.5.1.201412091616\r\nTi SDK : 4.0.0.v20150313181810\r\nCLI : 3.4.2\r\nAlloy : 1.5.1\r\nMAC Yosemite : 10.10.2\r\nIphone 6 - IOS 8.2\r\n", "updateAuthor": { "name": "lchoudhary", "key": "lchoudhary", "displayName": "Lokesh Choudhary", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2015-03-19T00:46:09.000+0000", "updated": "2015-03-19T00:46:09.000+0000" } ], "maxResults": 21, "total": 21, "startAt": 0 } } }