ssl: Bugfix: Use cypher suite's PRF in prf/5.
Kenneth Lakin <[email protected]> Tue, 3 May 2016 00:37:40 -0700
| Newsgroups | gmane.comp.lang.erlang.patches |
|---|---|
| Message-ID | <[email protected]> |
This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --===============9086908550973382217== Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="NxPhSUeDWR4msNkCmb1uBFxkb22LmhT26" This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --NxPhSUeDWR4msNkCmb1uBFxkb22LmhT26 Content-Type: multipart/mixed; boundary="XHBuCPPvVBSxoPhVO86g7b2ro3ISJ5qWh" From: Kenneth Lakin <[email protected]> To: [email protected] Message-ID: <[email protected]> Subject: ssl: Bugfix: Use cypher suite's PRF in prf/5. --XHBuCPPvVBSxoPhVO86g7b2ro3ISJ5qWh Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable The PR is at: https://github.com/erlang/otp/pull/1042 You should be able to fetch with: git fetch git://github.com/kennethlakin/otp.git tls-use-negotiated-prf And compare with: https://github.com/erlang/otp/compare/maint-18...kennethlakin:tls-use-neg= otiated-prf https://github.com/erlang/otp/compare/maint-18...kennethlakin:tls-use-neg= otiated-prf.patch The remainder of this message is the same as the text in the PR: TLS 1.2 allows the negotiated cipher to specify its own PRF algorithm. ssl:prf/5 currently follows a code path that uses hard-coded PRF algorithms that are always correct for TLS 1.0, always wrong for TLS 1.1, and sometimes correct for TLS 1.2. The TLS handshaking code calls tls_v1:prf/5 through another path, so it does not run into this bug. (Given that ssl:prf/5 was added to support EAP-TLS and friends, I'm probably one of a tiny handful of people who make use of this function. (EAP-TLS and friends use the output of the TLS PRF as keying material. If the authenticating server's keys don't match what the client thinks the keys should be, then the client bails out.)) The patch modifies ssl_handshake:prf to accept a PRF algorithm (rather than using the hard-coded one), and ssl_connection:handle_sync_event({prf ...) to pass the connection's negotiated PRF algorithm along to ssl_handshake:prf. It also adds code to test the output of ssl:prf/5. To demonstrate the bug and the correctness of the fix, run the following in an Erlang shell: dbg:start(). dbg:tracer(). dbg:tpl(tls_v1, prf, []). dbg:p(all, c). ssl:start(). Ciphers=3D{ciphers, [{ecdhe_rsa,aes_256_gcm,null,sha384}, {ecdhe_rsa,aes_256_cbc,sha384,sha384}]}. {ok, S}=3Dssl:connect("www.google.com", 443, [Ciphers]). ssl:prf(S, <<"">>, <<"">>, [<<"">>], 16). ssl:close(S). f(S). f(Ciphers). (Notice that we're only using ciphers that have a SHA384 PRF.) The buggy code produces the following output. (Random binary data has been elided. The PRF to be used is the first argument to tls_v1:prf. 5 is the SHA384 PRF, 4 is the SHA256 PRF, and both values are defined in ssl_record.hrl.)= 7> {ok, S}=3Dssl:connect("www.google.com", 443, [Ciphers]). (<0.59.0>) call tls_v1:prf(5,...,<<"master secret">>,[...,...],48) (<0.59.0>) call tls_v1:prf(5,...,"key expansion",[...,...],72) (<0.59.0>) call tls_v1:prf(5,...,"key expansion",[...,...],72) (<0.59.0>) call tls_v1:prf(5,...,<<"client finished">>,...,12) (<0.59.0>) call tls_v1:prf(5,...,<<"server finished">>,...,12) {ok,{sslsocket,{gen_tcp,#Port<0.892>,tls_connection, undefined}, <0.59.0>}} 8> ssl:prf(S, <<"">>, <<"">>, [<<"">>], 16). (<0.59.0>) call tls_v1:prf(4,<<>>,<<>>,[<<>>],16) {ok,<<166,249,145,171,43,95,158,232,6,60,17,90,183,180,0, 155>>} Notice how the first argument passed to tls_v1:prf/5 by way of the call to ssl:prf/5 is *not* the same as the first argument passed in during the handshaking process. The fixed code produces the following output: 7> {ok, S}=3Dssl:connect("www.google.com", 443, [Ciphers]). (<0.59.0>) call tls_v1:prf(5,...,<<"master secret">>,[...,...],48) (<0.59.0>) call tls_v1:prf(5,...,"key expansion",[...,...],72) (<0.59.0>) call tls_v1:prf(5,...,"key expansion",[...,...],72) (<0.59.0>) call tls_v1:prf(5,...,<<"client finished">>,...,12) (<0.59.0>) call tls_v1:prf(5,...,<<"server finished">>,...,12) {ok,{sslsocket,{gen_tcp,#Port<0.892>,tls_connection, undefined}, <0.59.0>}} 8> ssl:prf(S, <<"">>, <<"">>, [<<"">>], 16). (<0.59.0>) call tls_v1:prf(5,<<>>,<<>>,[<<>>],16) {ok,<<153,182,217,96,186,130,105,85,65,103,123,247,146, 91,47,106>>} Notice how the first argument passed to tls_v1:prf/5 by way of the call to ssl:prf/5 is the now same as the first argument passed in during the handshaking process. --XHBuCPPvVBSxoPhVO86g7b2ro3ISJ5qWh-- --NxPhSUeDWR4msNkCmb1uBFxkb22LmhT26 Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCAAGBQJXKFVEAAoJEDpEx4ha9HUKPKkP/jjeaGWn3C/FWc80JAkJHXle SjcuByIp+jvN7hbyNiR+gfFUF5wa5QmhuxesdFs4k7cSiryK3rRNLh21UwPXwoS8 PKbAU9ned0iamdkPx/ltQ9zfdSeI0maGvgPkovfvI9FlT9hNjF7jdkRNIw8RjeER iNctkC+kk8wunM0sH2rA34uUy4kUrIno7UmgVtof6Yk8wEZGWiaT0pH4NrH82Lwt 4SQ/NXTMMdhclUv0yJG6dZj8QJ8iX/BqGxftvzDBG1o1kuVAquvKwKy34fXckM9j qxzKTofCKZd2UzBbuouGCxQwGf3X/jM2SPAJt8fmn8dIxThsbPtaxoE16LIUOlry yjv8t0fE9CTqF2C1rOcGImJDz/pAwnSYo1BsYdBMeT7ZjUrywqjSy0ZLH4sZz5JP iKjPvxCmfkDeGch+WBsTLOiQxoCcfcdUjoFXIob4cNMxnQSHdpZDYWJm+R10ucm8 hqfqLiF828LN9gRgUrOdeJ/5ukByhD6HuOcpn8eCwCyl/bCY5u73NsbTUqWx73HU DhB8KAW0xQGWcUwaITTSnjhBLT5iuwM/ZFZ4TKPldqSlnxumn59z0EMvzkU3TcMZ QmMDnFFYEb/Qq75GglOUhqSey/3FZ+owCXI3bCuIANIVWhWP/uZedhEc7RKGzTjd JuD9knssIo+6hwb3UPZ7 =oqrQ -----END PGP SIGNATURE----- --NxPhSUeDWR4msNkCmb1uBFxkb22LmhT26-- --===============9086908550973382217== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ erlang-patches mailing list [email protected] http://erlang.org/mailman/listinfo/erlang-patches --===============9086908550973382217==--