Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/hackney_conn.erl
Original file line number Diff line number Diff line change
Expand Up @@ -761,10 +761,9 @@ connected({call, From}, {upgrade_to_ssl, _SslOpts}, #conn_data{transport = hackn
{keep_state_and_data, [{reply, From, ok}]};
connected({call, From}, {upgrade_to_ssl, SslOpts}, #conn_data{socket = Socket, host = Host, connect_options = ConnectOpts} = Data) ->
%% Upgrade TCP socket to SSL (e.g., after CONNECT proxy tunnel)
%% Get default SSL options with hostname verification
DefaultSslOpts = hackney_ssl:check_hostname_opts(Host),
%% Merge user-provided SSL options (they override defaults)
MergedSslOpts = hackney_util:merge_opts(DefaultSslOpts, SslOpts),
%% Use ssl_opts/2 to properly merge defaults with user options
%% (handles cacertfile vs cacerts correctly)
MergedSslOpts = hackney_ssl:ssl_opts(Host, [{ssl_options, SslOpts}]),
%% Add ALPN options for HTTP/2 negotiation
%% Check both SslOpts (from upgrade call) and ConnectOpts (from initial config)
AlpnOpts = case hackney_ssl:alpn_opts(SslOpts) of
Expand Down Expand Up @@ -2271,8 +2270,9 @@ do_tcp_connect(From, Data) ->
TransportOpts = proplists:delete(protocols, ConnectOpts),
Opts = case Transport of
hackney_ssl ->
DefaultSslOpts = hackney_ssl:check_hostname_opts(Host),
MergedSslOpts = hackney_util:merge_opts(DefaultSslOpts, SslOpts0),
%% Use ssl_opts/2 to properly merge defaults with user options
%% (handles cacertfile vs cacerts correctly)
MergedSslOpts = hackney_ssl:ssl_opts(Host, [{ssl_options, SslOpts0}]),
AlpnOpts = hackney_ssl:alpn_opts(ConnectOpts),
FinalSslOpts = hackney_util:merge_opts(MergedSslOpts, AlpnOpts),
TransportOpts ++ [{ssl_options, FinalSslOpts}];
Expand Down
28 changes: 28 additions & 0 deletions test/certs/ca.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCj1XbtZLafXR5i
h513pkjAHfj+Ox8d5BgayydNru4zZVMdsamxZO02ZAvhM2CBlJ0T2XLuxE/4ULUD
1nzH/58gz4ij78KMU5l77LRa2IwWYQSTotLIHR5CVkba8khgsj7sKrlOsvcEJW5+
jl5Eov6a5LMr8eB13wBlWeqrID0kwo5Ebw+soTzUrJn57u5FsUzklm4N+W+WgwR+
KawGss0Qg2YNA101tlIDWwH8VBqXxnr76T8fTdoEK+dqNYTUq2U7+HJlhHTJchj0
OesoS4gZfat244MsyFagrZNPsTrofOeO5vRiKgCOss0iAnrn6/yjfiuoJ+1RqVYH
FF9f9DFxAgMBAAECggEABqrerctYG8z3OjkM7WRC6G+n1RfcnLOuT/PV2AVfHBAa
9XXII0gpV7nzWlFEE43z5Q2HzgQHAaLuNPdnCWAjrpsHk21j4GBcGhUgY2SV8ei1
nhkFpT97HmXCuTEcRTQn16Zm93cU0rI/yI58c2RjQnQ9fvO3Z/ChBF7oDBoSJvNj
zZlhkrfhCJgujf5deQjk2td5zVDKBB7OkrBHM7nGdOyqPWwRBWHRrpCj2v2MKQOu
LjNcBwr7qE0jYA7D5y2M3AI2Bpof7IgFhnnvN9xkj8e6uvfMjd2y4gpOvxwdf3XO
ya+vAtcbI1PVgIj8KY6rHgMXtqkYfmfn9fq1Zy5pAQKBgQDc162OFK8twi9rmz9w
+H3dv8dEOtTbnviITEb9X8z7j6QcYpf3oJVcfGkNaz2Co4g/MDzkK7RD6XHeUvBo
T28JvskghVNMYO6HKf/2oiTPlwtH1Wdm6I0n5fo8L29a8IkXlnfpNmstI0vJsXXo
L5+pIyNLv6L9KfzhEq+UYK+ngQKBgQC96m24V7OAXw0YFbjEX/2P4CMlq2Wfe06r
OiqVmZH4pUASQ0q1N8CMrSCu1Y7MZzLaUuLdL8GwL0NGZMBMSimTt7pfZDDeDda4
xX22fYas+ZUZJAHu7CdvHH1MT9GEDp+G7XVY/LnruMSNwJ/lFOobNrcqRWz2ojru
44IjovAB8QKBgGAYRT/Oxk8t8P5sxlU8+1/TRDzvMJIEAXclYbp8xjAsV6e2SxQI
PxXIWNnq8Q/4Yp/EOKq8TatDWDX6dvucnN9rsg7BlPZmM0SDRQqnkUb3HYR7WowP
4uQakSFBLr4ubijiY3kKIea5NhAkdP68QkgRrxkV4TEx5QR24gm5bJWBAoGAY9tO
g54BcN8JiH9rXj3Gmg7VDCp5zYhNTfTQjUZpHR7ueGvPbUd6Q72IMMVzRwCAGZF5
XamNovDG48132uUnxVbWdO++ThNislaNChYoaOz2O3jWV2TuOxr0utpBJLl3ob9b
c0W3ED1fg9UjfZUontR/LIfCik+0wwT22XwDzFECgYBqcL9JWozhqVVOmEO6PqZe
ysVWZInS9REFyOTBz7C3csUnzX+7aFljjSB7H8BeJ/Q4rmvNJ33ueqnXAg/CnyDO
Ex+GiFHceCk5j5eS0r/uKhyrfL3wysYTDfOoN585n8unEJsif4hkRi6C52OhedwS
Sg+tHFiu58ngrgxCrniA2Q==
-----END PRIVATE KEY-----
19 changes: 19 additions & 0 deletions test/certs/ca.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDBTCCAe2gAwIBAgIUa2T0vunNiiG+w74wOqoY/wpfW1cwDQYJKoZIhvcNAQEL
BQAwEjEQMA4GA1UEAwwHVGVzdCBDQTAeFw0yNjAzMTgwNzI3NDFaFw0zNjAzMTUw
NzI3NDFaMBIxEDAOBgNVBAMMB1Rlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQCj1XbtZLafXR5ih513pkjAHfj+Ox8d5BgayydNru4zZVMdsamx
ZO02ZAvhM2CBlJ0T2XLuxE/4ULUD1nzH/58gz4ij78KMU5l77LRa2IwWYQSTotLI
HR5CVkba8khgsj7sKrlOsvcEJW5+jl5Eov6a5LMr8eB13wBlWeqrID0kwo5Ebw+s
oTzUrJn57u5FsUzklm4N+W+WgwR+KawGss0Qg2YNA101tlIDWwH8VBqXxnr76T8f
TdoEK+dqNYTUq2U7+HJlhHTJchj0OesoS4gZfat244MsyFagrZNPsTrofOeO5vRi
KgCOss0iAnrn6/yjfiuoJ+1RqVYHFF9f9DFxAgMBAAGjUzBRMB0GA1UdDgQWBBTc
WObZ/TNAq4tQqy34nNCttoc5FDAfBgNVHSMEGDAWgBTcWObZ/TNAq4tQqy34nNCt
toc5FDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAxnuB+uBwK
jzS/muqhi8l3ccGh8WvQy0ABLVBbxQ+IElTNCxA+zh6zCnMdmv7LqN7Q1sFcTsoq
aSsyvC5TPS6eVSuh4eB5ATY5bZD0J+X35OWd0+1vyDHFQN7fjgVGz09OFCbUyRfi
U934qbTEcD3gpv9LKs9WQnuKKouAPlIqrIDak/z9o4PsYP52Av2h3O+ThO+suBbD
a9IoNHru+I46xrqXsze8BzIVdnPYVpUxtsF440cErBeKonDzrQAWNIonut3ldsgG
JxvJQFl+itRAcKhOI9GvN2nSstkbYC6VaZ0EpzPqhfazuXz4Re4Te5NGa8/j78GI
V3UA40EJUz7c
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions test/certs/server.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCoQRXFhsXPwITJ
xvXpm6ShxKIE1BqSCqoaVPycpEHPEr0S3xTXgTfp53Xv0p2L65bucF2Yn4+1wonf
qAh796po/8jSI+Fzoh51tHs5OTvEGcL2qHUFBXvdpleQuf4MeMU3ouDx1zMrXjuw
DvCdwzCkOj6fA2v7+4BPfQATMosOy3vbTJKHv/HKXteg/Nbp1TZOwl3Pr9zGYXFw
5+6k2Qh+cdg/l3qT2HxhMBSKtlmmn5X4ofmjWOelly1v8WpCn5psjfvuoJnitA4U
Xc3dawdYp3/0rL+/BWTbXDDqxN7TE5DsTOhmDlWmCV8a1QSpzz8V+2MTEJ2F5+jr
oldmmMDrAgMBAAECggEARrQzBfKApbDtHC2zoRt6r1AGFalcEQrSOIaGMP0FepMR
SSDdjUIL0QsnEESdV/MEVeZ6Lmy+406Aya+/APkubzktlsDlOMZjrmrNbVqTtvBs
cWKQ6i9HwfjoyzSdgXguyBZ2GKqqIgtTYcSlcGZZxmmDbybs9dLWNJD+uxJ+RRSm
Qt/UYrPk9Ldkzze9wDRTv5bnMDgOayah4nYITBIsmbFEd+QBQYkjjzDecwHA3JrC
7qkRHK/YXerAUDfSu+kiilwaG9rL01p+GGduoB3T0/Ba/+xryOTiJxHAv/lbiG1C
cjOQBdj2NZvt37dZ56On7fZelh/z0VAxsNL5VbH24QKBgQDiDYTi+llYDQclnjf1
7owq+GNLtnqkOoxgCLL09H/4yvhpGRyl/sTWcJUmN30BIGf3JbsEdUlw8LpjbQqg
xG/+quoJzWhUdERE7ws077q7FS6oIuWR+Ebne010jOxR53K9TtG5fGka6krxmt/m
k5ZyGwoKWWrZaUVhUi1uEZTVvwKBgQC+i1pgcS1Exb4Ux6TkoD5pHKPLf1rJo4t5
gd0NAQwzBoWvKtzoFrWHmJc8EwumZjTylRFsCQ4dhunRwTyAga6st1qBp1102yLX
lTCfLeXz0+LlkwUNhu7fbOLmSsn6xwiTXoNONQE3xabSYO+i/FQYtJwVH4phwMHi
NARqPKFX1QKBgCwL+lLH+VTA5R2dYMYY/1L4J1D/c5JAnk2wJD66zZzK3/CKphxq
Miyer1FNCpyHlfqAbZqGyBKrtYXeH24IGNKEtynFzoh2Rz8vXP2poLcHf5nfguAY
gqhkTEljlEC5WpAspY0BAvHtqUC+rtYc9/mv7xrpJXrLmmtGOffykQ+9AoGAb5rL
usVPkIKKDT3KdSbupz5hKeZUVNp37RmFUgKVFKXzU2A1t7LlbKCRpFw7bKFczeFG
LRM4s068UWFvgI10tDFIz7wp3zIjPEZkDjgiAijPM0xjn0KzUyZB2EVh/ILroPWw
zvP43KPmTD7+3WYSE85lxXGN6ieu6EEzfM46amkCgYAyRF2RA/CsbdK0+aAQpcVB
51H36BpItwcGh2/CF84hEm7Xq8FZN2Xv0a3aZfMD/4gWIDR5GN/HqBhIe0rzSV9B
ijVoF8P8JuYkB9FbZnK5srLqrh/uZb3AsHOuEzt3YnF1Xkq2h+UggE3e6izA5tXh
32zpCo8kSaPbLDyQR191og==
-----END PRIVATE KEY-----
19 changes: 19 additions & 0 deletions test/certs/server.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDEjCCAfqgAwIBAgIUeHOpIj5w7HfcnQw9T0ShnnZ3BjMwDQYJKoZIhvcNAQEL
BQAwEjEQMA4GA1UEAwwHVGVzdCBDQTAeFw0yNjAzMTgwNzI3NDFaFw0zNjAzMTUw
NzI3NDFaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAKhBFcWGxc/AhMnG9embpKHEogTUGpIKqhpU/JykQc8SvRLf
FNeBN+nnde/SnYvrlu5wXZifj7XCid+oCHv3qmj/yNIj4XOiHnW0ezk5O8QZwvao
dQUFe92mV5C5/gx4xTei4PHXMyteO7AO8J3DMKQ6Pp8Da/v7gE99ABMyiw7Le9tM
koe/8cpe16D81unVNk7CXc+v3MZhcXDn7qTZCH5x2D+XepPYfGEwFIq2Waaflfih
+aNY56WXLW/xakKfmmyN++6gmeK0DhRdzd1rB1inf/Ssv78FZNtcMOrE3tMTkOxM
6GYOVaYJXxrVBKnPPxX7YxMQnYXn6OuiV2aYwOsCAwEAAaNeMFwwGgYDVR0RBBMw
EYcEfwAAAYIJbG9jYWxob3N0MB0GA1UdDgQWBBQGilSdZDqBe3dZwUVJU+dZSwWF
ZTAfBgNVHSMEGDAWgBTcWObZ/TNAq4tQqy34nNCttoc5FDANBgkqhkiG9w0BAQsF
AAOCAQEALQzkn2Ggt2UhtqpLDMaYwY3h5+beqOVeZ8MYp+IOeJWNfDF072TE6pYH
xiZYfJ+RdZePe7VqnQJEQsMMJ/6p5VEGSCNN0Zryz4by3Vu/JA3RX6JqRq55Al9I
1CPwn2Ii+dE8CJYRXG63tqqYzchmPVwfing7/YpT8D7zUpRmsd9oU8PTlpnxonvc
SmvZEBTf8PVEm6HlO/nPxOi0MvN8AkQ8EBH23qDWPsiAd6LN+nySVnukAPRlt+8Q
ZTM6KneidFluqTzbacnw/9njlH7fyQktsUDQh3wzQ6+x10PjfFa25Vi1L+kRvk7x
e3h+4kGHJQpRtEBQ3NoeaS0KccGahg==
-----END CERTIFICATE-----
59 changes: 59 additions & 0 deletions test/hackney_cacertfile_bug_test.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
%%% Test that cacertfile option is respected when making HTTPS requests.
%%%
%%% Currently fails because hackney_conn.erl bypasses hackney_ssl:ssl_opts/2
%%% and calls hackney_ssl:check_hostname_opts/1 directly, which always sets
%%% {cacerts, certifi:cacerts()}. Erlang SSL then ignores cacertfile.

-module(hackney_cacertfile_bug_test).
-include_lib("eunit/include/eunit.hrl").

-define(HTTPS_PORT, 8126).

cacertfile_test_() ->
{setup,
fun setup/0,
fun teardown/1,
[
{"cacertfile respected in ssl_opts/2", fun test_ssl_opts_handles_cacertfile/0},
{"cacertfile respected in request", fun test_request_with_cacertfile/0}
]}.

setup() ->
error_logger:tty(false),
{ok, _} = application:ensure_all_started(cowboy),
{ok, _} = application:ensure_all_started(hackney),

CertDir = cert_dir(),
CertFile = filename:join(CertDir, "server.pem"),
KeyFile = filename:join(CertDir, "server.key"),

Dispatch = cowboy_router:compile([{'_', [{"/[...]", test_http_resource, []}]}]),
{ok, _} = cowboy:start_tls(cacertfile_test_server,
[{certfile, CertFile},
{keyfile, KeyFile},
{port, ?HTTPS_PORT}],
#{env => #{dispatch => Dispatch}}),
ok.

teardown(_) ->
cowboy:stop_listener(cacertfile_test_server),
application:stop(cowboy),
application:stop(hackney),
error_logger:tty(true),
ok.

test_ssl_opts_handles_cacertfile() ->
CACertFile = filename:join(cert_dir(), "ca.pem"),
Options = [{ssl_options, [{cacertfile, CACertFile}]}],
SslOpts = hackney_ssl:ssl_opts("localhost", Options),
?assert(lists:keymember(cacertfile, 1, SslOpts)),
?assertNot(lists:keymember(cacerts, 1, SslOpts)).

test_request_with_cacertfile() ->
CACertFile = filename:join(cert_dir(), "ca.pem"),
Url = "https://localhost:" ++ integer_to_list(?HTTPS_PORT) ++ "/get",
Opts = [{ssl_options, [{cacertfile, CACertFile}]}, {pool, false}],
{ok, 200, _, _} = hackney:request(get, Url, [], <<>>, Opts).

cert_dir() ->
filename:join([filename:dirname(code:which(?MODULE)), "..", "test", "certs"]).
Loading