I'm relatively new to Erlang and want to write a small server that uses the client certificate to identify the client. The client should be able to use any public/private key pair without it being part of a certificate chain. I looked at the SSL examples from the OTP source code and used make_certs.erl to create the key pairs. I can connect using the created client certificate, but not using a self signed certificate.
How can I get the client certificate without validating it?
My sample code is currently:
-module(simple_server).
-export([start/0]).
keep_alive() ->
receive
Any -> io:format("Listening socket: ~p~n",[Any])
end.
start() ->
ssl:start(),
spawn(fun() ->
start_parallel_server(3333),
keep_alive()
end).
start_parallel_server(Port) ->
case ssl:listen(Port, [
binary,
{packet, 0},
{reuseaddr, true},
{active, true},
{certfile,"../etc/server/cert.pem"},
{keyfile,"../etc/server/key.pem"},
{cacertfile,"../etc/server/cacerts.pem"},
{verify,verify_peer},
{fail_if_no_peer_cert,true}
]) of
{ok,Listen} ->
spawn(fun() -> par_connect(Listen) end);
{error,Reason} ->
io:format("error ~p~n",[Reason])
end.
par_connect(Listen) ->
case ssl:transport_accept(Listen) of
{ok,Socket} ->
spawn(fun() -> par_connect(Listen) end),
ssl:ssl_accept(Socket),
print_cert(Socket),
get_request(Socket,[]);
{error,Reason} ->
io:format("Listening stopped (~p)~n",[Reason])
end.
print_cert(Socket) ->
case ssl:peercert(Socket) of
{ok,Cert} ->
io:format("Certificate: ~p~n",[Cert]);
{error,Reason} ->
io:format("Certificate error ~p~n",[Reason])
end.
get_request(Socket,L) ->
receive
{ssl, Socket, Bin} ->
io:format("Server received: ~p~n",[Bin]),
get_request(Socket,L);
{ssl_closed, Socket} ->
io:format("Socket did disconnect~n");
Reason ->
io:format("Client error: ~p~n",[Reason])
end.
You need to supply a custom path verification function to ssl:listen
that allows self-signed certificates.
The verify_fun
option (see the docs) lets you specify a function that is called when a certification verification error is encountered.
We can take the default implementation (given in the docs) and make sure the selfsigned_peer
case returns success:
{verify_fun, {fun(_, {bad_cert, selfsigned_peer}, UserState) ->
{valid, UserState}; %% Allow self-signed certificates
(_,{bad_cert, _} = Reason, _) ->
{fail, Reason};
(_,{extension, _}, UserState) ->
{unknown, UserState};
(_, valid, UserState) ->
{valid, UserState};
(_, valid_peer, UserState) ->
{valid, UserState}
end, []}}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With