{ "id": "168726", "key": "MOD-2347", "fields": { "issuetype": { "id": "2", "description": "A new feature of the product, which has yet to be developed.", "name": "New Feature", "subtask": false }, "project": { "id": "10034", "key": "MOD", "name": "Appcelerator Modules", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [ { "id": "19872", "name": "appcelerator.https 2.1.0", "archived": false, "released": true } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2017-10-22T08:42:10.000+0000", "created": "2017-07-03T02:58:00.000+0000", "priority": { "name": "Critical", "id": "1" }, "labels": [ "leaf-certificate", "trust-chain" ], "versions": [], "issuelinks": [], "assignee": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "updated": "2018-08-06T17:49:36.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": "15019", "name": "Https" } ], "description": "Basically you currently compare the public key of the provided certificate with the public key of the 0-indexed certificate in the site's certificate chain - the leaf certificate. I would prefer to make the index a variable. That way we can pin to the CA (or intermediate CA) so that the app does not need to be updated with every site's certificate update.\r\n", "attachment": [ { "id": "63459", "filename": "wellsfargo.cer", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2017-10-21T11:43:21.000+0000", "size": 1667, "mimeType": "application/x-x509-ca-cert" } ], "flagged": false, "summary": "[appcelerator.https] iOS/Android: Add option to pin to CA instead of leaf", "creator": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "environment": null, "comment": { "comments": [ { "id": "423324", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "Can you please describe what's exactly is not working when specifying a CA certificate (including an example to reproduce)? Also, is this relevant for both iOS and Android? Please let us know, so we can schedule it, thanks!", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2017-07-03T13:26:26.000+0000", "updated": "2017-07-03T13:26:26.000+0000" }, { "id": "423416", "author": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Basically you currently compare the public key of the provided certificate with the public key of the 0-indexed certificate in the site's certificate chain - the leaf certificate. I would prefer to make the index a variable. That way we can pin to the CA (or intermediate CA) so that the app does not need to be updated with every site's certificate update.\r\n\r\nI am happy to implement it my self - it is pretty straight forward - it is just this is a closed source (pro) module.", "updateAuthor": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-07-03T21:36:32.000+0000", "updated": "2017-07-03T21:36:32.000+0000" }, { "id": "423735", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "While we cannot provide the module source, we will be able to implement the feature for you. Would it fit for you to have a third argument passed to {{createX509CertificatePinningSecurityManager}} called {{trustChainIndex}}, defaulting to 0 (leaf) when not set? We would support it for both platforms of course.", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2017-07-09T07:28:40.000+0000", "updated": "2017-07-09T07:28:40.000+0000" }, { "id": "423736", "author": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Sounds good. Thanks.", "updateAuthor": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-07-09T08:37:35.000+0000", "updated": "2017-07-09T08:37:35.000+0000" }, { "id": "423738", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "PR: https://github.com/appcelerator-modules/appcelerator.https/pull/45/\r\n\r\nTest-case:\r\n{code:js}\r\n\r\nvar https = require('appcelerator.https');\r\n\r\n/*\r\n * Create a Security Manager for Titanium.Network.HTTPClient that\r\n * authenticates a currated set of HTTPS servers. It does this by\r\n * \"pinning\" an HTTPS server's DNS name to the public key contained in\r\n * the X509 certificate it uses for TLS communication. The public key\r\n * is embedded in an app by adding this X509 certificate to the app's\r\n * Resources directory.\r\n *\r\n * With such a \"pin\" in place, the security manager will guarantee\r\n * that all HTTPClient connections to this HTTPS server are to a\r\n * server that holds the private key corresponding to the public key\r\n * embedded in the app, therefore authenticating the server.\r\n *\r\n * This is what prevents \"Man-in-the-Middle\" attack.\r\n *\r\n * This example pins two URLs.\r\n *\r\n * The first URL, https://www.americanexpress.com, is pinned to the\r\n * public key in the X.509 certificate in the file named\r\n * wellsfargo.cer. This is intentionally an incorrect configuration.\r\n * Connections to https://www.americanexpress.com must fail since the\r\n * public key presented by the host will not match the configuration of the\r\n * security manager\r\n *\r\n * The second URL, https://www.wellsfargo.com, is pinned to the public\r\n * key in the X.509 certificate in the file named\r\n * wellsfargo.cer. This is configured correctly. Connections to\r\n * https://www.wellsfargo.com must succeed. Note that these request redirect.\r\n * The redirected request is not handled by the security manager since it is\r\n * not configured but will succeed if the system is able to validate the\r\n * certificate chain presented by the redirected host.\r\n *\r\n * The X.509 certificate files can have any name and extension you\r\n * wish, but they must be in the standard DER binary format.\r\n */\r\nvar securityManager = https.createX509CertificatePinningSecurityManager([{\r\n\turl: \"https://www.wellsfargo.com\",\r\n\tserverCertificate: \"wellsfargo.cer\",\r\n\ttrustChainIndex: 1 // 2nd certificate in the cert-chain (Symantec Class 3 Secure Server CA)\r\n}]);\r\n\r\nvar win = Titanium.UI.createWindow({\r\n\ttitle: 'Pin Example',\r\n\tbackgroundColor: 'white'\r\n});\r\n\r\nvar view = Ti.UI.createView({\r\n\tbackgroundColor: 'white',\r\n\tlayout: 'vertical',\r\n\twidth: Ti.UI.SIZE,\r\n\theight: Ti.UI.SIZE,\r\n\ttop:20\r\n});\r\n\r\nvar button1 = Titanium.UI.createButton({\r\n\ttitle: 'Load wellsfargo',\r\n\tcolor: 'green',\r\n\ttop:20,\r\n});\r\n\r\nvar label1 = Titanium.UI.createLabel({\r\n\ttext: 'Desc:',\r\n\tcolor: 'black',\r\n\ttop:20,\r\n});\r\n\r\nvar label2 = Titanium.UI.createLabel({\r\n\ttext: 'Status:',\r\n\tcolor: 'black',\r\n\ttop:20,\r\n});\r\n\r\nview.add(button1);\r\nview.add(label1);\r\nview.add(label2);\r\n\r\nwin.add(view);\r\nwin.open();\r\n\r\n/*\r\n * Create an HTTP client the same way you always have, but pass in an\r\n * (optional) Security Manager. In this example, we pass in the\r\n * \"Certificate Pinning Security Manager \" that I configured above.\r\n */\r\nfunction getXHR(url) {\r\n\tvar xhr = Ti.Network.createHTTPClient({\r\n\t\tonload: function(e) {\r\n\t\t\tlabel2.text = 'onload called. Request succeeded';\r\n\t\t},\r\n\t\tonerror: function(e) {\r\n\t\t\tlabel2.text = 'onerror called. Request failed.';\r\n\t\t},\r\n\t\ttimeout : 30000,\r\n\t\tsecurityManager: securityManager\r\n\t});\r\n\r\n\txhr.open('GET',url);\r\n\r\n\treturn xhr;\r\n}\r\n\r\nvar wf = \"https://www.wellsfargo.com\";\r\n\r\nbutton1.addEventListener('click',function(e){\r\n\tvar xhr = getXHR(wf);\r\n\tlabel1.text = 'SecurityManager is configured correctly for this request. Request must succeed. ';\r\n\tlabel1.color = 'green';\r\n\tlabel2.text = 'Desc:';\r\n\txhr.send();\r\n});\r\n{code}", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2017-07-09T15:42:47.000+0000", "updated": "2017-10-21T11:45:28.000+0000" }, { "id": "423741", "author": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Hans,\r\n\r\nI'm just looking at the test case for the following snippet: \r\n\r\n{code}\r\n\t{\r\n\t\turl: \"https://www.wellsfargo.com\",\r\n\t\tserverCertificate: \"wellsfargo.cer\",\r\n trustChainIndex: 1 // 2nd certificate in certificate chain\r\n\t}\r\n{code}\r\n\r\nI'd expect that the {{serverCertificate}} that would be provided would be the Symantic Class 3 Secure Server CA (intermediate CA) and that it could be reused for other server that are signed with that CA. (Rather than providing the current service certificate).\r\n\r\nThe need for this is that the CAs generally last longer than a server certificate and it avoids the need for timing an update with a certificate update.\r\n\r\nDoes that make sense?", "updateAuthor": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-07-09T21:56:27.000+0000", "updated": "2017-07-09T21:57:14.000+0000" }, { "id": "423745", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "[~dbankier] Yes, you are correct. In my case, I'm just assuming the user renames the CA certificate to match the example certificate, but in the end it's all about the certificate itself, not the name :-).\r\n\r\n*EDIT*: For QE: I've added the {{Symantec Class 3 Secure Server CA - G4}} certificate that is linked with Wells Fargo.", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2017-07-10T00:14:31.000+0000", "updated": "2017-07-10T00:34:22.000+0000" }, { "id": "423749", "author": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Thank you.", "updateAuthor": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-07-10T02:17:34.000+0000", "updated": "2017-07-10T02:17:34.000+0000" }, { "id": "424063", "author": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "body": "@hknoechel, any chance that I can an early release of the module? I'm happy to run with a beta build. Thanks.", "updateAuthor": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-07-13T08:53:21.000+0000", "updated": "2017-07-13T08:53:21.000+0000" }, { "id": "427874", "author": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Just checking in to see if there has been any updates. It has been In Review for a couple of months and curious whether it has already been completed and Jira not updated or just forgotten about.\r\n\r\nThanks.\r\n\r\nDavid", "updateAuthor": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-09-14T09:57:03.000+0000", "updated": "2017-09-14T09:57:03.000+0000" }, { "id": "427876", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "[~dbankier] It is still in review since we had two major releases that intercepted, sorry for that! Let me send you the module via mail today and we update the ticket once 6.3.0.GA is out of the door.\r\n\r\n*EDIT*: Your JIRA email-address does not seem to exist, please reach out to me via Twitter (@hansemannnn), thx!", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2017-09-14T12:02:52.000+0000", "updated": "2017-09-14T12:09:58.000+0000" }, { "id": "427880", "author": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Thanks Hans. I just sent you an email. I don't really use twitter anymore.", "updateAuthor": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-09-14T13:36:19.000+0000", "updated": "2017-09-14T13:36:19.000+0000" }, { "id": "427882", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "Got your email, but your provider keeps blocking the response. Sorry ...\r\n\r\n{code}\r\n SMTP error from remote mail server after pipelined end of data:\r\n 552-5.7.0 This message was blocked because its content presents a potential\r\n 552-5.7.0 security issue. Please visit\r\n 552-5.7.0 https://support.google.com/mail/?p=BlockedMessage to review our\r\n 552 5.7.0 message content and attachment content guidelines. f22si13471345wrf.172 - gsmtp\r\nReporting-MTA: dns; smtprelay04.ispgateway.de\r\n{code}", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2017-09-14T15:05:39.000+0000", "updated": "2017-09-14T15:05:39.000+0000" }, { "id": "427905", "author": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "body": "My guess is it is a zip file and gmail is blocking it. Can you send me a link? Or share via dropbox (same email address).", "updateAuthor": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-09-14T18:57:39.000+0000", "updated": "2017-09-14T18:57:39.000+0000" }, { "id": "429284", "author": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Hi Hans,\r\n\r\nI have been testing the build you sent me and the `trustChainIndex` property doesn't seem to do anything.\r\n\r\nDavid ", "updateAuthor": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-10-19T10:57:50.000+0000", "updated": "2017-10-19T10:57:50.000+0000" }, { "id": "429285", "author": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Forget to mention, testing on iOS.", "updateAuthor": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-10-19T10:58:51.000+0000", "updated": "2017-10-19T10:58:51.000+0000" }, { "id": "429321", "author": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Hans, for the builds you sent me, it works on Android but not on iOS.\r\n", "updateAuthor": { "name": "dbankier", "key": "dbankier", "displayName": "David Bankier", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-10-20T07:05:38.000+0000", "updated": "2017-10-20T07:05:38.000+0000" }, { "id": "429382", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "Thanks David, we'll revisit iOS! Can you specify what exactly does not work? Does it still select the leaf only? During my testing, I was able to see the CA-cert when selecting a different index which indicated everything works. Did you ensure that the version of the module in your project was updated?\r\n\r\n*EDIT*: I added some debugging by looping through the available certs:\r\n{code}\r\n2017-10-21 13:42:54.092 test_https[4421:133780] 0: \r\n2017-10-21 13:42:59.994 test_https[4421:133780] 1: \r\n2017-10-21 13:43:04.133 test_https[4421:133780] 2: \r\n{code}\r\nThe second one (index = 1) is selected and the connection gets approved properly.", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2017-10-21T09:03:08.000+0000", "updated": "2017-10-21T11:44:00.000+0000" }, { "id": "440238", "author": { "name": "emerriman", "key": "emerriman", "displayName": "Eric Merriman ", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Cleaning up older fixed issues. If this issue should not have been closed as fixed, please reopen.", "updateAuthor": { "name": "emerriman", "key": "emerriman", "displayName": "Eric Merriman ", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-08-06T17:49:36.000+0000", "updated": "2018-08-06T17:49:36.000+0000" } ], "maxResults": 21, "total": 21, "startAt": 0 } } }