Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.22.0 causes CLIENT ALERT: Fatal - Handshake Failure when sending GET request with TLS options #759

Open
luismiramirez opened this issue Feb 24, 2025 · 15 comments · May be fixed by #763
Open

Comments

@luismiramirez
Copy link

Description

When calling :hackney.request/4 with TLS options including custom hostname verification as described in the trace below, we're receiving handshake failures. This is a regression as we've confirmed this works correctly in Hackney 1.21.0.

Steps to reproduce

  1. Install Hackney 1.22.0
  2. Make a HTTPS request with the following options:
:hackney.request(:get, "https://d135dj0rjqvssy.cloudfront.net/0.36.0/appsignal-aarch64-darwin-all-static.tar.gz", [], "", [
  {:ssl_options, [
    {:verify, :verify_peer},
    {:cacertfile, "/path/to/cacert.pem"},
    {:versions, [:'tlsv1.3', :'tlsv1.2']},
    {:customize_hostname_check, [{:match_fun, :public_key.pkix_verify_hostname_match_fun(:https)}]}
  ]}
])

Trace

[hackney trace 80 <0.283.0> 2025:02:24 13:39:45 4543] request 
   Content: [{module,hackney},
             {line,313},
             {method,get},
             {url,
                 {hackney_url,hackney_ssl,https,
                     <<"d135dj0rjqvssy.cloudfront.net">>,
                     <<"/0.36.0/appsignal-aarch64-darwin-all-static.tar.gz">>,
                     <<"/0.36.0/appsignal-aarch64-darwin-all-static.tar.gz">>,
                     <<>>,<<>>,"d135dj0rjqvssy.cloudfront.net",443,<<>>,<<>>}},
             {headers,[]},
             {body,<<>>},
             {options,
                 [{ssl_options,
                      [{verify,verify_peer},
                       {cacertfile,
                           <<"/Users/luismiramirez/code/handshake/_build/dev/lib/appsignal/priv/cacert.pem">>},
                       {versions,['tlsv1.3','tlsv1.2']},
                       {customize_hostname_check,
                           [{match_fun,#Fun<public_key.6.112534691>}]}]}]}]
[hackney trace 60 <0.283.0> 2025:02:24 13:39:45 4543] no proxy env setup, request without proxy 
   Content: [{module,hackney},{line,695}]
[hackney trace 60 <0.283.0> 2025:02:24 13:39:45 4543] connect 
   Content: [{module,hackney_connect},
             {line,32},
             {transport,hackney_ssl},
             {host,"d135dj0rjqvssy.cloudfront.net"},
             {port,443},
             {dynamic,true}]
[hackney trace 80 <0.283.0> 2025:02:24 13:39:45 4544] no socket in the pool 
   Content: [{module,hackney_pool},{line,88},{pool,default}]
[hackney trace 60 <0.283.0> 2025:02:24 13:39:45 4544] happy eyeballs, try to connect using IPv6 
   Content: [{module,hackney_happy},
             {line,32},
             {hostname,"d135dj0rjqvssy.cloudfront.net"},
             {port,443}]
[hackney trace 80 <0.387.0> 2025:02:24 13:39:45 4609] happy eyeball: failed to connect 
   Content: [{module,hackney_happy},{line,129},{error,{error,nxdomain}}]
[hackney trace 80 <0.388.0> 2025:02:24 13:39:45 4610] try to connect 
   Content: [{module,hackney_happy},
             {line,132},
             {ip,{18,154,56,68}},
             {type,inet}]
[hackney trace 80 <0.388.0> 2025:02:24 13:39:45 4623] success to connect 
   Content: [{module,hackney_happy},
             {line,135},
             {ip,{18,154,56,68}},
             {type,inet}]
[hackney trace 80 <0.283.0> 2025:02:24 13:39:45 4624] happy_connect ~p 
   Content: [{module,hackney_happy},{line,78},{ok,#Port<0.320>}]

14:39:45.655 [notice] TLS :client: In state :wait_cert_cr at ssl_handshake.erl:2186 generated CLIENT ALERT: Fatal - Handshake Failure
 - {:bad_cert,
 {:hostname_check_failed, {:requested, {18, 154, 56, 68}},
  {:received, [dNSName: ~c"cloudfront.net", dNSName: ~c"*.cloudfront.net"]}}}
[hackney trace 80 <0.283.0> 2025:02:24 13:39:45 4656] connect error 
   Content: [{module,hackney_pool},
             {line,108},
             {pool,default},
             {error,
                 {error,
                     {tls_alert,
                         {handshake_failure,
                             "TLS client: In state wait_cert_cr at ssl_handshake.erl:2186 generated CLIENT ALERT: Fatal - Handshake Failure\n {bad_cert,\n     {hostname_check_failed,\n         {requested,{18,154,56,68}},\n         {received,\n             [{dNSName,\"cloudfront.net\"},{dNSName,\"*.cloudfront.net\"}]}}}"}}}}]
luismiramirez added a commit to appsignal/appsignal-elixir that referenced this issue Feb 24, 2025
Due to an error on Hackney 1.22.0 when sending TLS requests, limit it to
the latest compatible version.

More info: benoitc/hackney#759
luismiramirez added a commit to appsignal/appsignal-elixir that referenced this issue Feb 24, 2025
Due to an error on Hackney 1.22.0 when sending TLS requests, limit it to
the latest compatible version.

More info: benoitc/hackney#759
@benoitc
Copy link
Owner

benoitc commented Feb 25, 2025

can you check with #760 this should fix your issue.

@luismiramirez
Copy link
Author

@benoitc the issue is gone. Thank you very much!

@luismiramirez
Copy link
Author

It is still happening after 1.23.0, the difference is that this time it fails when the request is a POST. GET requests work fine.

@benoitc
Copy link
Owner

benoitc commented Feb 25, 2025

there is no difference between POST and GET on connect normally. can you share a trace of your issue?

@benoitc
Copy link
Owner

benoitc commented Feb 25, 2025

@luismiramirez can you try to passe the option {reuse_session, true} to the SSL options and let me know about the result?

@luismiramirez
Copy link
Author

Sure! Here's the trace. No handshake error anymore, now it is a connection error:

Validating Push API key: [hackney trace 80 <0.94.0> 2025:02:26 09:03:30 4555] request 
   Content: [{module,hackney},
             {line,313},
             {method,post},
             {url,
                 {hackney_url,hackney_ssl,https,<<"push.appsignal.com">>,
                     <<"/1/auth?name=&hostname=&api_key=1234&environment=dev">>,
                     <<"/1/auth">>,
                     <<"name=&hostname=&api_key=1234&environment=dev">>,
                     <<>>,"push.appsignal.com",443,<<>>,<<>>}},
             {headers,
                 [{<<"Content-Type">>,<<"application/json; charset=UTF-8">>}]},
             {body,<<>>},
             {options,
                 [{ssl_options,
                      [{reuse_session,true},
                       {verify,verify_peer},
                       {cacertfile,
                           <<"/Users/luismiramirez/code/handshake/_build/dev/lib/appsignal/priv/cacert.pem">>},
                       {versions,['tlsv1.3','tlsv1.2']},
                       {customize_hostname_check,
                           [{match_fun,#Fun<public_key.6.112534691>}]}]},
                  {pool,appsignal_transmitter}]}]
[hackney trace 60 <0.94.0> 2025:02:26 09:03:30 4556] no proxy env setup, request without proxy 
   Content: [{module,hackney},{line,695}]
[hackney trace 60 <0.94.0> 2025:02:26 09:03:30 4557] connect 
   Content: [{module,hackney_connect},
             {line,32},
             {transport,hackney_ssl},
             {host,"push.appsignal.com"},
             {port,443},
             {dynamic,true}]
[hackney trace 80 <0.94.0> 2025:02:26 09:03:30 4558] no socket in the pool 
   Content: [{module,hackney_pool},{line,88},{pool,appsignal_transmitter}]
[hackney trace 60 <0.94.0> 2025:02:26 09:03:30 4560] happy eyeballs, try to connect using IPv6 
   Content: [{module,hackney_happy},
             {line,32},
             {hostname,"push.appsignal.com"},
             {port,443},
             {timeout,8000}]
[hackney trace 80 <0.94.0> 2025:02:26 09:03:30 4630] happy connect: try IPv4 only 
   Content: [{module,hackney_happy},{line,37}]
[hackney trace 80 <0.230.0> 2025:02:26 09:03:30 4630] try to connect 
   Content: [{module,hackney_happy},
             {line,145},
             {ip,{185,191,3,125}},
             {type,inet}]
[hackney trace 80 <0.230.0> 2025:02:26 09:03:30 4669] success to connect 
   Content: [{module,hackney_happy},
             {line,148},
             {ip,{185,191,3,125}},
             {type,inet}]
[hackney trace 80 <0.94.0> 2025:02:26 09:03:30 4669] happy_connect ~p 
   Content: [{module,hackney_happy},{line,91},{ok,#Port<0.21>}]
[hackney trace 80 <0.94.0> 2025:02:26 09:03:30 4674] connect error 
   Content: [{module,hackney_pool},
             {line,108},
             {pool,appsignal_transmitter},
             {error,{error,{options,{reuse_session,true}}}}]
[hackney trace 80 <0.94.0> 2025:02:26 09:03:30 4674] connect error 
   Content: [{module,hackney_connect},{line,238}]

@benoitc
Copy link
Owner

benoitc commented Feb 26, 2025

My bad it should be reuse_sessions (with an s at the end) . Sorry for that. If you can retry that would be helpful.

@luismiramirez
Copy link
Author

Sure, here's the handshake error again:

Validating Push API key: [hackney trace 80 <0.94.0> 2025:02:26 11:31:35 4485] request 
   Content: [{module,hackney},
             {line,313},
             {method,post},
             {url,
                 {hackney_url,hackney_ssl,https,<<"push.appsignal.com">>,
                     <<"/1/auth?name=&hostname=&api_key=1234&environment=dev">>,
                     <<"/1/auth">>,
                     <<"name=&hostname=&api_key=1234&environment=dev">>,
                     <<>>,"push.appsignal.com",443,<<>>,<<>>}},
             {headers,
                 [{<<"Content-Type">>,<<"application/json; charset=UTF-8">>}]},
             {body,<<>>},
             {options,
                 [{ssl_options,
                      [{reuse_sessions,true},
                       {verify,verify_peer},
                       {cacertfile,
                           <<"/Users/luismiramirez/code/handshake/_build/dev/lib/appsignal/priv/cacert.pem">>},
                       {versions,['tlsv1.3','tlsv1.2']},
                       {customize_hostname_check,
                           [{match_fun,#Fun<public_key.6.112534691>}]}]},
                  {pool,appsignal_transmitter}]}]
[hackney trace 60 <0.94.0> 2025:02:26 11:31:35 4486] no proxy env setup, request without proxy 
   Content: [{module,hackney},{line,695}]
[hackney trace 60 <0.94.0> 2025:02:26 11:31:35 4487] connect 
   Content: [{module,hackney_connect},
             {line,32},
             {transport,hackney_ssl},
             {host,"push.appsignal.com"},
             {port,443},
             {dynamic,true}]
[hackney trace 80 <0.94.0> 2025:02:26 11:31:35 4488] no socket in the pool 
   Content: [{module,hackney_pool},{line,88},{pool,appsignal_transmitter}]
[hackney trace 60 <0.94.0> 2025:02:26 11:31:35 4490] happy eyeballs, try to connect using IPv6 
   Content: [{module,hackney_happy},
             {line,32},
             {hostname,"push.appsignal.com"},
             {port,443},
             {timeout,8000}]
[hackney trace 80 <0.94.0> 2025:02:26 11:31:35 4525] happy connect: try IPv4 only 
   Content: [{module,hackney_happy},{line,37}]
[hackney trace 80 <0.230.0> 2025:02:26 11:31:35 4525] try to connect 
   Content: [{module,hackney_happy},
             {line,145},
             {ip,{185,191,3,93}},
             {type,inet}]
[hackney trace 80 <0.230.0> 2025:02:26 11:31:35 4565] success to connect 
   Content: [{module,hackney_happy},
             {line,148},
             {ip,{185,191,3,93}},
             {type,inet}]
[hackney trace 80 <0.94.0> 2025:02:26 11:31:35 4565] happy_connect ~p 
   Content: [{module,hackney_happy},{line,91},{ok,#Port<0.21>}]

12:31:35.671 [notice] TLS :client: In state :certify at ssl_handshake.erl:2186 generated CLIENT ALERT: Fatal - Handshake Failure
 - {:bad_cert,
 {:hostname_check_failed, {:requested, {185, 191, 3, 93}},
  {:received, [dNSName: ~c"push.appsignal.com"]}}}
[hackney trace 80 <0.94.0> 2025:02:26 11:31:35 4678] connect error 
   Content: [{module,hackney_pool},
             {line,108},
             {pool,appsignal_transmitter},
             {error,
                 {error,
                     {tls_alert,
                         {handshake_failure,
                             "TLS client: In state certify at ssl_handshake.erl:2186 generated CLIENT ALERT: Fatal - Handshake Failure\n {bad_cert,\n     {hostname_check_failed,\n         {requested,{185,191,3,93}},\n         {received,[{dNSName,\"push.appsignal.com\"}]}}}"}}}}]
[hackney trace 80 <0.94.0> 2025:02:26 11:31:35 4678] connect error 
   Content: [{module,hackney_connect},{line,238}]

Validating failed, reason:

  {:tls_alert, {:handshake_failure, ~c"TLS client: In state certify at ssl_handshake.erl:2186 generated CLIENT ALERT: Fatal - Handshake Failure\n {bad_cert,\n     {hostname_check_failed,\n         {requested,{185,191,3,93}},\n         {received,[{dNSName,\"push.appsignal.com\"}]}}}"}}

@benoitc
Copy link
Owner

benoitc commented Feb 26, 2025

this is because the host enforse domain name verifictaion. I am looking at it.

@benoitc benoitc linked a pull request Feb 26, 2025 that will close this issue
@benoitc
Copy link
Owner

benoitc commented Feb 26, 2025

@luismiramirez please check #763 and let me know. This should fix the issue you reported.

@benoitc
Copy link
Owner

benoitc commented Feb 28, 2025

@luismiramirez were you able to check?

@luismiramirez
Copy link
Author

@benoitc yes, I pasted the trace in #763

Validating Push API key: [hackney trace 80 <0.94.0> 2025:02:27 10:31:10 4677] request 
   Content: [{module,hackney},
             {line,313},
             {method,post},
             {url,
                 {hackney_url,hackney_ssl,https,<<"push.appsignal.com">>,
                     <<"/1/auth?name=&hostname=&api_key=1234&environment=dev">>,
                     <<"/1/auth">>,
                     <<"name=&hostname=&api_key=1234&environment=dev">>,
                     <<>>,"push.appsignal.com",443,<<>>,<<>>}},
             {headers,
                 [{<<"Content-Type">>,<<"application/json; charset=UTF-8">>}]},
             {body,<<>>},
             {options,
                 [{ssl_options,
                      [{verify,verify_peer},
                       {cacertfile,
                           <<"/Users/luismiramirez/code/handshake/_build/dev/lib/appsignal/priv/cacert.pem">>},
                       {versions,['tlsv1.3','tlsv1.2']},
                       {customize_hostname_check,
                           [{match_fun,#Fun<public_key.6.112534691>}]}]},
                  {pool,appsignal_transmitter}]}]
[hackney trace 60 <0.94.0> 2025:02:27 10:31:10 4678] request without proxy 
   Content: [{module,hackney},{line,686}]
[hackney trace 60 <0.94.0> 2025:02:27 10:31:10 4679] connect 
   Content: [{module,hackney_connect},
             {line,32},
             {transport,hackney_ssl},
             {host,"push.appsignal.com"},
             {port,443},
             {dynamic,true}]
[hackney trace 80 <0.94.0> 2025:02:27 10:31:10 4685] no socket in the pool 
   Content: [{module,hackney_pool},{line,88},{pool,appsignal_transmitter}]
[hackney trace 80 <0.94.0> 2025:02:27 10:31:10 4686] connect error 
   Content: [{module,hackney_connect},{line,238}]

Validating failed, reason:

  :checkout_failure

@benoitc
Copy link
Owner

benoitc commented Mar 1, 2025

@luismiramirez sorry I missed that. checking

@silviucpp
Copy link

I have same issue with 1.23.0 and I cannot replicate with 1.20.1

@benoitc
Copy link
Owner

benoitc commented Mar 3, 2025

@silviucpp can you share the url you're trying. I don't reproduce when #763 is applied .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants