diff options
author | Magnus Ahltorp <map@kth.se> | 2015-04-07 20:59:27 +0200 |
---|---|---|
committer | Linus Nordberg <linus@nordberg.se> | 2015-04-08 17:51:51 +0200 |
commit | 1d1ea78c07f389172237d990c18d47dbba8014f5 (patch) | |
tree | ff12f1df33c629e229567a856d93caa9c02c363e /src/plop_httputil.erl | |
parent | ff09515865ed871f6fe55db37ed0df7e8bbc8a1c (diff) |
Added hostname verification for SSL connections
Diffstat (limited to 'src/plop_httputil.erl')
-rw-r--r-- | src/plop_httputil.erl | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/src/plop_httputil.erl b/src/plop_httputil.erl index 2d840aa..3b1c104 100644 --- a/src/plop_httputil.erl +++ b/src/plop_httputil.erl @@ -5,6 +5,7 @@ -module(plop_httputil). -export([request/4]). -include_lib("hackney/include/hackney_lib.hrl"). +-include_lib("public_key/include/public_key.hrl"). get_auth_header(Headers) -> case hackney_headers:get_value("X-Catlfish-Auth", Headers) of @@ -20,15 +21,54 @@ add_auth(Method, Path, Headers, Data) -> lager:debug("sent auth header: ~p", [AuthHeader]), [{"X-Catlfish-Auth", AuthHeader} | Headers]. +get_cert_hostname(Cert) -> + TBSCert = Cert#'OTPCertificate'.tbsCertificate, + Subject = TBSCert#'OTPTBSCertificate'.subject, + {rdnSequence, RDNs} = Subject, + CNs = lists:map(fun([#'AttributeTypeAndValue'{type=?'id-at-commonName', value=Value}]) -> + Value; + (_) -> + none + end, RDNs), + case [CN || CN <- CNs, CN /= none] of + [{utf8String, BinCN} | _] when is_binary(BinCN) -> + binary_to_list(BinCN); + [CN | _] -> + CN; + [] -> + "" + end. + +verify_fun(_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; +verify_fun(_,{extension, _}, UserState) -> + {unknown, UserState}; +verify_fun(_, valid, UserState) -> + {valid, UserState}; +verify_fun(Cert, valid_peer, UserState) -> + CertHostname = get_cert_hostname(Cert), + case lists:keyfind(check_hostname, 1, UserState) of + {check_hostname, CertHostname} -> + {valid, UserState}; + {check_hostname, ExpectedHostname} -> + lager:info("Expected hostname ~p but certificate has hostname ~p", [ExpectedHostname, CertHostname]), + {fail, "Hostname does not match"}; + false -> + {valid, UserState} + end. + request(DebugTag, URL, Headers, RequestBody) -> Starttime = os:timestamp(), ParsedURL = hackney_url:parse_url(URL), CACertFile = application:get_env(catlfish, https_cacertfile, none), - #hackney_url{path = Path} = ParsedURL, + #hackney_url{path = Path, host = Host} = ParsedURL, lager:debug("~s: sending http request to ~p", [DebugTag, URL]), case hackney:connect(ParsedURL, - [{ssl_options, [{cacertfile, CACertFile}]}]) of + [{ssl_options, [{cacertfile, CACertFile}, + {verify, verify_peer}, + {verify_fun, {fun verify_fun/3, [{check_hostname, Host}]}} + ]}]) of {ok, ConnRef} -> lager:debug("~s: connected to ~p", [DebugTag, URL]), |