<div dir="ltr">Hi!<div><br></div><div>Sorry for the late reply, been really busy.  Firstly I have not changed my mind about breaking specs, but actually the latest TLS draft is validating this behaviour and even recommending that it be handled so in earlier versions in defiance to the specs, so we are looking into including it after all.</div><div><br></div><div>And yes doing it in the verify fun would mean to first pass all certificates and saving them in the user state, and then redo the validation with</div><div>a new sorting of the chain, but you need not do the verification manually, you can call the same public_key API function that ssl does. It would work the only downside is that it all checks will be run twice. </div><div><br></div><div>Regards Ingela Erlang/OTP team - Ericsson AB</div><div><br></div><div><br></div><div><div class="gmail_extra"><br><div class="gmail_quote">2014-08-12 22:24 GMT+02:00 Ben Murphy <span dir="ltr"><<a href="mailto:benmmurphy@gmail.com" target="_blank">benmmurphy@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Cheers,<br>
<br>
Do you know how I would go about writing the verify function? It looks<br>
like it is called for every certificate in the chain from the last<br>
certificate to the first certificate and I can either fail or pass at<br>
each step. If I could know which cert was the 'first' one then I could<br>
just succeed every certificate and then rebuild the chain when I reach<br>
the first certificate and return pass or fail depending on whether i<br>
thought it was valid. But it doesn't look like the verify function has<br>
any concept of where it is in the chain relative to the first<br>
certificate. I suspect the only safe way of doing it will be to always<br>
return success in the verify function and build up the cert chain in<br>
ets (or somewhere else) then after the ssl handshake is completed<br>
manually validate the certificate chain.<br>
<div class="HOEnZb"><div class="h5"><br>
On Tue, Aug 12, 2014 at 7:21 PM, Ingela Andin <<a href="mailto:ingela.andin@gmail.com">ingela.andin@gmail.com</a>> wrote:<br>
> Hi!<br>
><br>
> 2014-08-12 12:01 GMT+02:00 Ben Murphy <<a href="mailto:benmmurphy@gmail.com">benmmurphy@gmail.com</a>>:<br>
><br>
>> I agree that these chains break the spec. The problem is almost<br>
>> everyone accepts these chains. So if you don't accept these chains<br>
>> then you are going to run into compatibility issues. I've tested<br>
>> safari/firefox/chrome/openssl/golang/java and all these<br>
>> implementations accept these chains.<br>
>><br>
>> If you look at the implementations this is a deliberately coded feature:<br>
>><br>
>> <a href="http://golang.org/src/pkg/crypto/x509/verify.go" rel="noreferrer" target="_blank">http://golang.org/src/pkg/crypto/x509/verify.go</a><br>
>> func (c *Certificate) Verify(opts VerifyOptions) (chains<br>
>> [][]*Certificate, err error) {<br>
>><br>
>> I think most implementations treat the first certificate as the<br>
>> clients certificate and the rest of the certificates as possible<br>
>> intermediaries between the clients certificate and a trusted<br>
>> certificate and try to build a chain based on that.<br>
>><br>
>><br>
><br>
> Just because many people got it wrong does not make it right.<br>
> If you want to interop with implementations that do not follow the spec, you<br>
> can do it with<br>
> help of the verify fun. It might not be a compelling solution and it might<br>
> give some performance penalty,<br>
> but it is doable. We do not desire to be bug-compatible with other<br>
> implementations and make compromises that<br>
> also might compromise with security.<br>
><br>
> Regards Ingela Erlang/OTP team - Ericsson AB<br>
><br>
><br>
><br>
>><br>
>> On Tue, Aug 12, 2014 at 9:40 AM, Andreas Schultz <<a href="mailto:aschultz@tpip.net">aschultz@tpip.net</a>><br>
>> wrote:<br>
>> > Hi Ben,<br>
>> ><br>
>> > ----- Original Message -----<br>
>> >> Hi Ingela,<br>
>> >><br>
>> >> So the real server I'm having trouble with is not public. But I have a<br>
>> >> made up server that is configured in a similar fashion.<br>
>> >><br>
>> >> <a href="https://test.fonix.io/" rel="noreferrer" target="_blank">https://test.fonix.io/</a><br>
>> >><br>
>> >> I've just added an extra cert to the end of the chain. This validates<br>
>> >> correctly in chrome and with curl on the command line.<br>
>> >><br>
>> >> <a href="https://test.fonix.io:444/" rel="noreferrer" target="_blank">https://test.fonix.io:444/</a><br>
>> >><br>
>> >> Where this is an extra cert added to the end of the chain and the<br>
>> >> order of the chain is broken. This validates correctly in chrome and<br>
>> >> with curl on the command line.<br>
>> >><br>
>> >> I think some browsers/ssl implementations may also accept chains where<br>
>> >> the first certificate in chain is not the client certificate but nginx<br>
>> >> won't let me test this scenario :)<br>
>> ><br>
>> > That would violate the standard. from RFC 2246 (TLS 1.0), Section 7.4.2:<br>
>> ><br>
>> >    certificate_list<br>
>> >        This is a sequence (chain) of X.509v3 certificates. The sender's<br>
>> >        certificate must come first in the list. Each following<br>
>> >        certificate must directly certify the one preceding it. Because<br>
>> >        certificate validation requires that root keys be distributed<br>
>> >        independently, the self-signed certificate which specifies the<br>
>> >        root certificate authority may optionally be omitted from the<br>
>> >        chain, under the assumption that the remote end must already<br>
>> >        possess it in order to validate it in any case.<br>
>> ><br>
>> > RFC 5246 (TLS 1.2) adds this:<br>
>> ><br>
>> >    The following rules apply to the certificates sent by the server:<br>
>> ><br>
>> >    -  The certificate type MUST be X.509v3, unless explicitly negotiated<br>
>> >       otherwise (e.g., [TLSPGP]).<br>
>> ><br>
>> >    -  The end entity certificate's public key (and associated<br>
>> >       restrictions) MUST be compatible with the selected key exchange<br>
>> >       algorithm.<br>
>> ><br>
>> > So the ordering is strict, no unrelated certificates are permitted<br>
>> > within the chain. This wording leaves it open whether a unrelated<br>
>> > certificated is permitted at the end of the chain. However, I would<br>
>> > rather choose the stricter interpretation and consider any unrelated<br>
>> > certificate an error.<br>
>> ><br>
>> > The certificates on your server port 443 are:<br>
>> ><br>
>> >  0<br>
>> > s:/serialNumber=oVMlbmYif-Pcg7kbO6LFKlAd0LjtU6Uw/C=GB/ST=London/L=London/O=Orca<br>
>> > Digital Ltd/OU=IT/CN=*.<a href="http://fonix.io" rel="noreferrer" target="_blank">fonix.io</a><br>
>> >    i:/C=US/O=GeoTrust, Inc./CN=GeoTrust SSL CA<br>
>> >  1 s:/C=US/O=GeoTrust, Inc./CN=GeoTrust SSL CA<br>
>> >    i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA<br>
>> >  2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA<br>
>> >    i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority<br>
>> >  3 s:/C=US/O=Google Inc/CN=Google Internet Authority G2<br>
>> >    i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA<br>
>> ><br>
>> > The chain for Number 0, 1 and 2 seems to be ok. However the Number 3<br>
>> > certificate is obsolete and IMHO an error.<br>
>> ><br>
>> ><br>
>> > The certificates on your server port 444 are:<br>
>> ><br>
>> > Certificate chain<br>
>> >  0<br>
>> > s:/serialNumber=oVMlbmYif-Pcg7kbO6LFKlAd0LjtU6Uw/C=GB/ST=London/L=London/O=Orca<br>
>> > Digital Ltd/OU=IT/CN=*.<a href="http://fonix.io" rel="noreferrer" target="_blank">fonix.io</a><br>
>> >    i:/C=US/O=GeoTrust, Inc./CN=GeoTrust SSL CA<br>
>> >  1 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA<br>
>> >    i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority<br>
>> >  2 s:/C=US/O=GeoTrust, Inc./CN=GeoTrust SSL CA<br>
>> >    i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA<br>
>> >  3 s:/C=US/O=Google Inc/CN=Google Internet Authority G2<br>
>> >    i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA<br>
>> ><br>
>> > So, Number 0 is ok, Number 1 is not the issuer of Number 0, so this IS<br>
>> > invalid, Number 2 is the issuer of Number 0, and Number 3 is unrelated<br>
>> > to any of them.<br>
>> ><br>
>> > To summarize:<br>
>> ><br>
>> > I believe Erlang is correct rejecting those certificate chains and<br>
>> > Chrome and wget (or probably really OpenSSL) need to be fixed to<br>
>> > properly reject those.<br>
>> ><br>
>> > Andreas<br>
>> ><br>
>> >><br>
>> >> I don't think I would be able to use verify_fun to safely ignore<br>
>> >> arbitrary extra certificates while not accepting untrusted chains. I<br>
>> >> believe I would need a whitelist of extra certificates to ignore which<br>
>> >> is problematic because things will explode when the server makes<br>
>> >> changes that they think are 'safe'.<br>
>> >><br>
>> >> On Mon, Aug 11, 2014 at 3:59 PM, Ingela Andin <<a href="mailto:ingela.andin@gmail.com">ingela.andin@gmail.com</a>><br>
>> >> wrote:<br>
>> >> > HI!<br>
>> >> ><br>
>> >> > 2014-08-11 16:16 GMT+02:00 Ben Murphy <<a href="mailto:benmmurphy@gmail.com">benmmurphy@gmail.com</a>>:<br>
>> >> ><br>
>> >> >> (I originally sent this to erlang-bugs but it doesn't look like it<br>
>> >> >> made it there)<br>
>> >> >><br>
>> >> >> We have a problem where an SSL server sends back a certificate chain<br>
>> >> >> that is invalid according to the TLS 1.2 specification and erlang<br>
>> >> >> rejects this chain with an unknown ca error. However, openssl and<br>
>> >> >> browsers will accept this chain because they are less strict about<br>
>> >> >> validation.<br>
>> >> >><br>
>> >> >> The chain looks something like:<br>
>> >> >><br>
>> >> >> 0. Server Cert issued by Intermediate Cert<br>
>> >> >> 1. Intermediate Cert issued by Root Cert<br>
>> >> >> 2. Root Cert issued by Root Cert<br>
>> >> >> 3. Unrelated certificate<br>
>> >> >> 4. Unrelated certificate<br>
>> >> ><br>
>> >> ><br>
>> >> ><br>
>> >> > What server is sending such a chain? Could you give me a concrete<br>
>> >> > example,maybe of list if you do not want to expose<br>
>> >> > it to the world.<br>
>> >> ><br>
>> >> ><br>
>> >> ><br>
>> >> >><br>
>> >> >><br>
>> >> >> Which is invalid according to: <a href="http://www.ietf.org/rfc/rfc5246.txt" rel="noreferrer" target="_blank">http://www.ietf.org/rfc/rfc5246.txt</a><br>
>> >> >><br>
>> >> >>    certificate_list<br>
>> >> >>       This is a sequence (chain) of certificates.  The sender's<br>
>> >> >>       certificate MUST come first in the list.  Each following<br>
>> >> >>       certificate MUST directly certify the one preceding it.<br>
>> >> >> Because<br>
>> >> >>       certificate validation requires that root keys be distributed<br>
>> >> >>       independently, the self-signed certificate that specifies the<br>
>> >> >> root<br>
>> >> >>       certificate authority MAY be omitted from the chain, under the<br>
>> >> >>       assumption that the remote end must already possess it in<br>
>> >> >> order to<br>
>> >> >>       validate it in any case<br>
>> >> >><br>
>> >> >> Looking at the openssl code they start at the beginning of the chain<br>
>> >> >> then recursively find the issuer in order to build up a chain. While<br>
>> >> >> the erlang ssl code assumes the last certificate in the chain is the<br>
>> >> >> root CA (ssl_certificate:trusted_cert_and_path).<br>
>> >> >><br>
>> >> ><br>
>> >> > It assumes that the last certificate is the ROOT or the certificate<br>
>> >> > just<br>
>> >> > before<br>
>> >> > the ROOT (as the ROOT cert may be left out as you said above) and if<br>
>> >> > the ROOT is left out it will try to find the ROOT in its database. If<br>
>> >> > the<br>
>> >> > ROOT is part<br>
>> >> > of the chain it will still be looked up to make sure we already have<br>
>> >> > it.<br>
>> >> ><br>
>> >> ><br>
>> >> >> Maybe this is more of a feature request than a bug. But I was<br>
>> >> >> wondering if it would be possible for erlang to either accept these<br>
>> >> >> dodgy chains, provide an option when connecting to accept these<br>
>> >> >> dodgy<br>
>> >> >> chains or allow users to supply a function to modify the certificate<br>
>> >> >> chain before validation takes place.<br>
>> >> ><br>
>> >> ><br>
>> >> ><br>
>> >> > You can use the verify_fun to accept any path validation errors you<br>
>> >> > want,<br>
>> >> > at your own risk as you are lowering the security requirements by<br>
>> >> > doing so.<br>
>> >> ><br>
>> >> > [...]<br>
>> >> ><br>
>> >> ><br>
>> >> > Regards Ingela Erlang/OTP team - Ericsson AB<br>
>> >> _______________________________________________<br>
>> >> erlang-questions mailing list<br>
>> >> <a href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a><br>
>> >> <a href="http://erlang.org/mailman/listinfo/erlang-questions" rel="noreferrer" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
>> >><br>
>> ><br>
>> > --<br>
>> > --<br>
>> > Dipl. Inform.<br>
>> > Andreas Schultz<br>
>> ><br>
>> > email: <a href="mailto:as@travelping.com">as@travelping.com</a><br>
>> > phone: <a href="tel:%2B49-391-819099-224" value="+49391819099224">+49-391-819099-224</a><br>
>> > mobil: <a href="tel:%2B49-170-2226073" value="+491702226073">+49-170-2226073</a><br>
>> ><br>
>> > ------------------- enabling your networks -------------------<br>
>> ><br>
>> > Travelping GmbH               phone:         <a href="tel:%2B49-391-819099229" value="+49391819099229">+49-391-819099229</a><br>
>> > Roentgenstr. 13               fax:           <a href="tel:%2B49-391-819099299" value="+49391819099299">+49-391-819099299</a><br>
>> > D-39108 Magdeburg             email:       <a href="mailto:info@travelping.com">info@travelping.com</a><br>
>> > GERMANY                       web:   <a href="http://www.travelping.com" rel="noreferrer" target="_blank">http://www.travelping.com</a><br>
>> ><br>
>> > Company Registration: Amtsgericht Stendal Reg No.:   HRB 10578<br>
>> > Geschaeftsfuehrer: Holger Winkelmann | VAT ID No.: DE236673780<br>
>> > --------------------------------------------------------------<br>
><br>
><br>
</div></div></blockquote></div><br></div></div></div>