summaryrefslogtreecommitdiff
path: root/src/rebar_pkg_resource.erl
diff options
context:
space:
mode:
authorTristan Sloughter <t@crashfast.com>2015-07-18 17:39:25 -0500
committerTristan Sloughter <t@crashfast.com>2015-07-18 17:40:09 -0500
commit3485f08a03fa8ff70c94decbd445f7b64982873c (patch)
tree6b61cfda5dfcfbfb812dfff213e056c94104fd3f /src/rebar_pkg_resource.erl
parent6f95911d3244c063222b4b4bcbb6c2e2271c5f4d (diff)
add ssl cert validation, unless OTP version is too old
Diffstat (limited to 'src/rebar_pkg_resource.erl')
-rw-r--r--src/rebar_pkg_resource.erl62
1 files changed, 61 insertions, 1 deletions
diff --git a/src/rebar_pkg_resource.erl b/src/rebar_pkg_resource.erl
index 450ff1e..62208a6 100644
--- a/src/rebar_pkg_resource.erl
+++ b/src/rebar_pkg_resource.erl
@@ -10,6 +10,7 @@
,make_vsn/1]).
-include("rebar.hrl").
+-include_lib("public_key/include/OTP-PUB-KEY.hrl").
lock(_AppDir, Source) ->
Source.
@@ -94,7 +95,7 @@ make_vsn(_) ->
request(Url, ETag) ->
case httpc:request(get, {Url, [{"if-none-match", ETag} || ETag =/= false]},
- [{relaxed, true}],
+ [{ssl, [ssl_opts(Url)]}, {relaxed, true}],
[{body_format, binary}],
rebar) of
{ok, {{_Version, 200, _Reason}, Headers, Body}} ->
@@ -120,3 +121,62 @@ etag(Path) ->
{error, _} ->
false
end.
+
+ssl_opts(Url) ->
+ case check_ssl_version() of
+ true ->
+ {ok, {_, _, Hostname, _, _, _}} = http_uri:parse(ec_cnv:to_list(Url)),
+ VerifyFun = {fun ssl_verify_hostname:verify_fun/3, [{check_hostname, Hostname}]},
+ CACerts = cacerts(),
+ [{verify, verify_peer}, {depth, 2}, {cacerts, CACerts}
+ ,{partial_chain, fun partial_chain/1}, {verify_fun, VerifyFun}];
+ false ->
+ ?WARN("Insecure HTTPS request (peer verification disabled), please update to OTP 17.4 or later", []),
+ [{verify, verify_none}]
+ end.
+
+partial_chain(Certs) ->
+ Certs1 = [{Cert, public_key:pkix_decode_cert(Cert, otp)} || Cert <- Certs],
+ CACerts = cacerts(),
+ CACerts1 = [public_key:pkix_decode_cert(Cert, otp) || Cert <- CACerts],
+
+ case ec_lists:find(fun({_, Cert}) ->
+ check_cert(CACerts1, Cert)
+ end, Certs1) of
+ {ok, Trusted} ->
+ {trusted_ca, element(1, Trusted)};
+ _ ->
+ unknown_ca
+ end.
+
+extract_public_key_info(Cert) ->
+ ((Cert#'OTPCertificate'.tbsCertificate)#'OTPTBSCertificate'.subjectPublicKeyInfo).
+
+cacerts() ->
+ Pems = public_key:pem_decode(rebar_cacerts:cacerts()),
+ [Der || {'Certificate', Der, _} <- Pems].
+
+check_cert(CACerts, Cert) ->
+ lists:any(fun(CACert) ->
+ extract_public_key_info(CACert) == extract_public_key_info(Cert)
+ end, CACerts).
+
+check_ssl_version() ->
+ case application:get_key(ssl, vsn) of
+ {ok, Vsn} ->
+ parse_vsn(Vsn) >= {5, 3, 6};
+ _ ->
+ false
+ end.
+
+parse_vsn(Vsn) ->
+ version_pad(string:tokens(Vsn, ".")).
+
+version_pad([Major]) ->
+ {list_to_integer(Major), 0, 0};
+version_pad([Major, Minor]) ->
+ {list_to_integer(Major), list_to_integer(Minor), 0};
+version_pad([Major, Minor, Patch]) ->
+ {list_to_integer(Major), list_to_integer(Minor), list_to_integer(Patch)};
+version_pad([Major, Minor, Patch | _]) ->
+ {list_to_integer(Major), list_to_integer(Minor), list_to_integer(Patch)}.