使用 Erlang 无需验证即可获取客户端证书
Get client certificate without validation using Erlang
我对 Erlang 比较陌生,想编写一个使用客户端证书来识别客户端的小型服务器。客户端应该能够使用任何 public/private 密钥对,而无需将其作为证书链的一部分。我查看了 OTP 源代码中的 SSL 示例,并使用 make_certs.erl 创建了密钥对。我可以使用创建的客户端证书进行连接,但不能使用自签名证书。
如何在不验证的情况下获取客户端证书?
我的示例代码目前是:
-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.
您需要向 ssl:listen
提供允许自签名证书的自定义路径验证功能。
verify_fun
选项 (see the docs) 允许您指定在遇到认证验证错误时调用的函数。
我们可以采用默认实现(在文档中给出)并确保 selfsigned_peer
案例 returns 成功:
{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, []}}
我对 Erlang 比较陌生,想编写一个使用客户端证书来识别客户端的小型服务器。客户端应该能够使用任何 public/private 密钥对,而无需将其作为证书链的一部分。我查看了 OTP 源代码中的 SSL 示例,并使用 make_certs.erl 创建了密钥对。我可以使用创建的客户端证书进行连接,但不能使用自签名证书。
如何在不验证的情况下获取客户端证书?
我的示例代码目前是:
-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.
您需要向 ssl:listen
提供允许自签名证书的自定义路径验证功能。
verify_fun
选项 (see the docs) 允许您指定在遇到认证验证错误时调用的函数。
我们可以采用默认实现(在文档中给出)并确保 selfsigned_peer
案例 returns 成功:
{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, []}}