konklone/shaaaaaaaaaaaaa

Cannot check IPv6 website

Opened this issue · 16 comments

Attempting to check an IPv6-only website, in my case https://game.flyingpenguintech.org/ returns an error: "Command failed: gethostbyname failure connect:errno=0"

A quick glance at the codebase looks as though you are shelling out to "openssl -s_client". This is known not to support IPv6 and probably never will: https://plus.google.com/+MichaelStapelberg/posts/YKVxPMxF8m6

Please consider using a tool that supports IPv6, such as gnutls-cli:
$ echo -n | gnutls-cli --print-cert -p 443 game.flyingpenguintech.org

I would very much like to support IPv6, but I don't know if I want to switch the backbone from OpenSSL to GnuTLS. I don't know much about GnuTLS, it doesn't seem to be used very widely at all, and I'm not sure how well maintained it is. There are, for better or worse, very very few IPv6-only websites today, and so I don't think the overall impact here is very high.

If you can point to a different approach, I'm open to it. For example, an in-Node library that does the TLS work itself might be worth it, even if it's less widely supported than OpenSSL, because it would save me from shelling out at all. I did that for reading x509 details in #30.

There are, for better or worse, very very few IPv6-only websites today, and so I don't think the overall impact here is very high.

And yet people like Google and Facebook consider the impact to be enough to support IPv6.

And yet people like Google and Facebook consider the impact to be enough to support IPv6.

Absolutely, but those websites are also available over IPv4 (which is why this SHA-1 tool can check them using openssl).

I'm a big supporter of IPv6, it's the future -- I just don't think the few IPv6-only websites out there are worth tearing things up over at the moment. :/

I was directed to the web checker by my cert vendor, ssls.com. The cert is installed on an IPv6-only site. The web checker failed to check my site. This a bug, with a high impact to me.

I took the time to file the bug report, and even suggest a possible fix. You did not agree with that fix, but it was suggested nonetheless. Now, I'm not a Node programmer (I'm more of a Python guy), so I don't have any more in the way of code to contribute. However, closing this report keeps it off the Open issues list (linked as "Lend a hand" from the description page), making it unfindable by someone who may know of a solution more to your liking.

You claim to be a "big supporter" of IPv6, but your code does not reflect this. It is 2014, two years after World IPv6 Launch. Any new code should be tested against IPv6 before release. Your claim and your action are contradictory.

IPv6 is not the future. It is a reality right now. Again: a user has bothered to file a bug report (with suggested fix!) against your software. Don't close the door in their face.

v6-only sites aren't the only problem. Even with dual-stacked websites, you can't assume that a site uses the same certificate on v4 and v6 -- you need to check them both before you can declare a site free of SHA-1.

Here's what I do locally in some of my scripts:

listenport=$(shuf -i 10000-65000 -n 1)
socat tcp-listen:"$listenport" tcp-connect:"$host":"$port" 2>/dev/null &
echo -n | openssl s_client -connect localhost:$listenport

which is a bit hideous, but no worse than openssl s_client being a v4-only network application in 2014, and it saves porting the entire thing to gnutls-cli.

is there a particular reason that the tls api built into node.js isn't being used? That would be better than shelling out anyway.

is there a particular reason that the tls api built into node.js isn't being used? That would be better than shelling out anyway.

If the site's work can be done with the Node tls API, I'd welcome that -- I moved a previous openssl command into using the x509 Node module instead in #30. I wasn't familiar with the tls API, so yeah, I'm definitely open to that.

I'm not sure what Node's IPv6 support is, or whether it would solve the issue. Since I'm having a rush of traffic and some memory issues, avoiding shelling out at all would be helpful.

I'm not entirely sure we can do this. Having a little play around with Node's tls API and I can make a connection to my site. The obvious thing to do is to use the getPeerCertificate() method. Firstly for my site it returns:

{ subject: 
   { C: 'GB',
     ST: 'Greater Manchester',
     L: 'Manchester',
     O: 'Jonathan Barnes',
     CN: 'sha2.jonnybarnes.uk',
     emailAddress: 'webmaster@jonnybarnes.uk' },
  issuer: 
   { C: 'IL',
     O: 'StartCom Ltd.',
     OU: 'Secure Digital Certificate Signing',
     CN: 'StartCom Class 2 Primary Intermediate Server CA' },
  subjectaltname: 'DNS:sha2.jonnybarnes.uk, DNS:jonnybarnes.uk, DNS:*.jonnybarnes.uk',
  modulus: 'DC78E8AFDCD080EECE6B86DA359778783985B4C0C3C20BCCF21237877A28A35CBC1841F755A953561C9646E82E949461CE6FC7E6FBDE927BA1231D3BA5089CBCEF663197E2E7459D693B4B2FFD575DDF67C213C2D9B67704FFD10D95A187E430E168995DB1FB209345528EE3729E799EF25687E8B02C9908404D444961D40F6FD24CA3AC05FFA9965D6D89FE6B9B8B6D105E7961B01EF3753498F9420762F98F25BB8C4BEEB312F4EAAEF6D2F47B5F365BA617DADFB08E9A0AAB841D18701F6A5DF5CFE75DD10D7A0B9C49DE041631624515DB6C3EC1363936357AFD664A89D179D1D6B7ABE09F8F0DC9DE6660444C3444D7B35B0BF77A2D1DF6A3B4BE95CD73',
  exponent: '10001',
  valid_from: 'Aug 30 10:04:53 2014 GMT',
  valid_to: 'Aug 30 06:21:02 2016 GMT',
  fingerprint: 'C3:15:ED:60:52:4E:3F:7C:99:3E:50:B9:0C:B9:EB:97:40:EF:17:14',
  ext_key_usage: [ '1.3.6.1.5.5.7.3.2', '1.3.6.1.5.5.7.3.1' ] }

So how can we tell what algorithm was used by the issuer?

And secondly I don't know how to get the intermediate certificates.

@jonnybarnes If we can get the raw cert text, each cert can be read in by the x509 code we have in the rest of the tool, which pulls out the signature algorithm. Right now, the results of shelling out to openssl are just the ASCII-armored text of each certificate, which are fed into the x509 library.

So what we need from the tls module is for it to fetch, from an IPv4 or IPv6 site, the text of the client and intermediate certificates. I just messed around with tls myself and I couldn't figure out how to extract the certificate text. If anyone has any ideas (or any other Node modules which do this, and which support IPv6 connections), I'm all ears.

@konklone I give up, I'm a PHP guy. If you clone/fork this repo: https://github.com/jonnybarnes/JTLS, then run npm install then run node example.js your terminal will display the cert chain for my site in ASCII form (-----BEGIN CERTIFICATE----- etc.) which can then be consumed by x509 I believe.

However its using console.log and I'm getting bitten by the facts thst Node is asynchronous and that this works differently in JS so I'm struggling to get it into a form that can be integrated with sha{13}.

Ideally it'd be something like

var tls = new TLSRequest(port, domain);
var certs = tls.certs;

and certs would be the cert chain, but I can't get that to work :(

I've got a little bit further in my fork, tls.certs will ultimately be an array containing the site certs that can be fed into an x509 parser. My issue at the moment, is if you just call tls.certs its an empty array.

I think the way of doing this is to have TLSRequest emit an event we can listen for to know when tls.certs has been populated, but I'm struggling on that part.

@jonnybarnes, this is definitely coming along! I think the code is more likely to look like this:

var tls = new TLSRequest(port, domain, function(certs) {
  // do stuff with certs
});

Or, it could look like this:

var tls = new TLSRequest(port, domain);
tls.getCerts(function(certs) {
  // do stuff with certs
});

In other words, no need to fight against the async. So the function in the file you're working on could look a bit likehthis:

function TLSRequest(port, host, callback) {
  this._recordBuffer = null;
  this.certs = [];
  // ... stuff ...
  fetchSomeStuff(function(certString) {
    var certs = parseCerts(certString);
    callback(certs);
  });
}

or something. The point is, have the callback available, so you can fire it whenever you have the certs parsed.

As this issue looks like it's being worked on, shouldn't it also be reopened?

Sure. But I'd also rather continue discussion about the migration in a separate ticket, since it's really about switching the tool to use a Node-based solution over openssl. If this proves to provide IPv6 support, which I think/hope it will, then this would be addressed as well.

I think forge is out of the question for now. It only supports:

  • TLS_RSA_WITH_AES_128_CBC_SHA
  • TLS_RSA_WITH_AES_256_CBC_SHA

Neither of which are enabled in your TLS setup that I'm using along with 18f websites.

A note that @mbrand1 has submitted a PR which refactors the site to use the tls module to support IPv6 sites, in #84. I'm reviewing it there, and since it's a major refactor, any other 👀 on it are welcome.