Titanium JIRA Archive
Appcelerator Modules (MOD)

[MOD-2347] [appcelerator.https] iOS/Android: Add option to pin to CA instead of leaf

GitHub Issuen/a
TypeNew Feature
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2017-10-22T08:42:10.000+0000
Affected Version/sn/a
Fix Version/sappcelerator.https 2.1.0
ComponentsHttps
Labelsleaf-certificate, trust-chain
ReporterDavid Bankier
AssigneeHans Knöchel
Created2017-07-03T02:58:00.000+0000
Updated2018-08-06T17:49:36.000+0000

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.

Attachments

FileDateSize
wellsfargo.cer2017-10-21T11:43:21.000+00001667

Comments

  1. Hans Knöchel 2017-07-03

    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!
  2. David Bankier 2017-07-03

    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. I am happy to implement it my self - it is pretty straight forward - it is just this is a closed source (pro) module.
  3. Hans Knöchel 2017-07-09

    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.
  4. David Bankier 2017-07-09

    Sounds good. Thanks.
  5. Hans Knöchel 2017-07-09

    PR: https://github.com/appcelerator-modules/appcelerator.https/pull/45/ Test-case:
       
       var https = require('appcelerator.https');
       
       /*
        * Create a Security Manager for Titanium.Network.HTTPClient that
        * authenticates a currated set of HTTPS servers. It does this by
        * "pinning" an HTTPS server's DNS name to the public key contained in
        * the X509 certificate it uses for TLS communication. The public key
        * is embedded in an app by adding this X509 certificate to the app's
        * Resources directory.
        *
        * With such a "pin" in place, the security manager will guarantee
        * that all HTTPClient connections to this HTTPS server are to a
        * server that holds the private key corresponding to the public key
        * embedded in the app, therefore authenticating the server.
        *
        * This is what prevents "Man-in-the-Middle" attack.
        *
        * This example pins two URLs.
        *
        * The first URL, https://www.americanexpress.com, is pinned to the
        * public key in the X.509 certificate in the file named
        * wellsfargo.cer. This is intentionally an incorrect configuration.
        * Connections to https://www.americanexpress.com must fail since the
        * public key presented by the host will not match the configuration of the
        * security manager
        *
        * The second URL, https://www.wellsfargo.com, is pinned to the public
        * key in the X.509 certificate in the file named
        * wellsfargo.cer. This is configured correctly. Connections to
        * https://www.wellsfargo.com must succeed. Note that these request redirect.
        * The redirected request is not handled by the security manager since it is
        * not configured but will succeed if the system is able to validate the
        * certificate chain presented by the redirected host.
        *
        * The X.509 certificate files can have any name and extension you
        * wish, but they must be in the standard DER binary format.
        */
       var securityManager = https.createX509CertificatePinningSecurityManager([{
       	url: "https://www.wellsfargo.com",
       	serverCertificate: "wellsfargo.cer",
       	trustChainIndex: 1 // 2nd certificate in the cert-chain (Symantec Class 3 Secure Server CA)
       }]);
       
       var win = Titanium.UI.createWindow({
       	title: 'Pin Example',
       	backgroundColor: 'white'
       });
       
       var view = Ti.UI.createView({
       	backgroundColor: 'white',
       	layout: 'vertical',
       	width: Ti.UI.SIZE,
       	height: Ti.UI.SIZE,
       	top:20
       });
       
       var button1 = Titanium.UI.createButton({
       	title: 'Load wellsfargo',
       	color: 'green',
       	top:20,
       });
       
       var label1 = Titanium.UI.createLabel({
       	text: 'Desc:',
       	color: 'black',
       	top:20,
       });
       
       var label2 = Titanium.UI.createLabel({
       	text: 'Status:',
       	color: 'black',
       	top:20,
       });
       
       view.add(button1);
       view.add(label1);
       view.add(label2);
       
       win.add(view);
       win.open();
       
       /*
        * Create an HTTP client the same way you always have, but pass in an
        * (optional) Security Manager. In this example, we pass in the
        * "Certificate Pinning Security Manager " that I configured above.
        */
       function getXHR(url) {
       	var xhr = Ti.Network.createHTTPClient({
       		onload: function(e) {
       			label2.text = 'onload called. Request succeeded';
       		},
       		onerror: function(e) {
       			label2.text = 'onerror called. Request failed.';
       		},
       		timeout : 30000,
       		securityManager: securityManager
       	});
       
       	xhr.open('GET',url);
       
       	return xhr;
       }
       
       var wf = "https://www.wellsfargo.com";
       
       button1.addEventListener('click',function(e){
       	var xhr = getXHR(wf);
       	label1.text = 'SecurityManager is configured correctly for this request. Request must succeed. ';
       	label1.color = 'green';
       	label2.text = 'Desc:';
       	xhr.send();
       });
       
  6. David Bankier 2017-07-09

    Hans, I'm just looking at the test case for the following snippet:
       	{
       		url: "https://www.wellsfargo.com",
       		serverCertificate: "wellsfargo.cer",
                       trustChainIndex: 1 // 2nd certificate in certificate chain
       	}
       
    I'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). The 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. Does that make sense?
  7. Hans Knöchel 2017-07-10

    [~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 :-). *EDIT*: For QE: I've added the Symantec Class 3 Secure Server CA - G4 certificate that is linked with Wells Fargo.
  8. David Bankier 2017-07-10

    Thank you.
  9. David Bankier 2017-07-13

    @hknoechel, any chance that I can an early release of the module? I'm happy to run with a beta build. Thanks.
  10. David Bankier 2017-09-14

    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. Thanks. David
  11. Hans Knöchel 2017-09-14

    [~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. *EDIT*: Your JIRA email-address does not seem to exist, please reach out to me via Twitter (@hansemannnn), thx!
  12. David Bankier 2017-09-14

    Thanks Hans. I just sent you an email. I don't really use twitter anymore.
  13. Hans Knöchel 2017-09-14

    Got your email, but your provider keeps blocking the response. Sorry ...
           SMTP error from remote mail server after pipelined end of data:
           552-5.7.0 This message was blocked because its content presents a potential
           552-5.7.0 security issue. Please visit
           552-5.7.0  https://support.google.com/mail/?p=BlockedMessage to review our
           552 5.7.0 message content and attachment content guidelines. f22si13471345wrf.172 - gsmtp
        Reporting-MTA: dns; smtprelay04.ispgateway.de
        
  14. David Bankier 2017-09-14

    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).
  15. David Bankier 2017-10-19

    Hi Hans, I have been testing the build you sent me and the trustChainIndex property doesn't seem to do anything. David
  16. David Bankier 2017-10-19

    Forget to mention, testing on iOS.
  17. David Bankier 2017-10-20

    Hans, for the builds you sent me, it works on Android but not on iOS.
  18. Hans Knöchel 2017-10-21

    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? *EDIT*: I added some debugging by looping through the available certs:
        2017-10-21 13:42:54.092 test_https[4421:133780] 0: <cert(0x7fe9e9d25310) s: www.wellsfargo.com i: Symantec Class 3 Secure Server CA - G4>
        2017-10-21 13:42:59.994 test_https[4421:133780] 1: <cert(0x7fe9ea03f800) s: Symantec Class 3 Secure Server CA - G4 i: VeriSign Class 3 Public Primary Certification Authority - G5>
        2017-10-21 13:43:04.133 test_https[4421:133780] 2: <cert(0x7fe9ea063a00) s: VeriSign Class 3 Public Primary Certification Authority - G5 i: VeriSign Class 3 Public Primary Certification Authority - G5>
        
    The second one (index = 1) is selected and the connection gets approved properly.
  19. Eric Merriman 2018-08-06

    Cleaning up older fixed issues. If this issue should not have been closed as fixed, please reopen.

JSON Source