Adding mqtt_client

This commit is contained in:
Stephane Bourque
2020-12-04 00:22:24 -08:00
parent 23d83940f7
commit 355770995b
9 changed files with 234 additions and 54 deletions

View File

@@ -48,6 +48,7 @@
cert = <<>> :: binary(),
decrypt = <<>> :: binary(),
csr = <<>> :: binary(),
cacert = <<>> :: binary(),
attributes = #{} :: attribute_list()
}).
@@ -66,6 +67,7 @@
cert = <<>> :: binary(),
decrypt = <<>> :: binary(),
csr = <<>> :: binary(),
cacert = <<>> :: binary(),
attributes = #{} :: attribute_list()
}).

View File

@@ -165,6 +165,7 @@
keep_alive = 0 :: integer(),
client_identifier = <<>> :: binary(),
will_topic = <<>> :: binary(),
will_message = <<>> :: binary(),
will_properties = [] :: list(),
will_payload = <<>> :: binary(),
username = <<>> :: binary(),
@@ -271,7 +272,7 @@
packet_type = 0 :: integer(),
flags = 0 :: integer(),
remaining_length = 0 :: integer(),
variable_header }).
variable_header = none :: none | mqtt_msg_any() }).
-record(mqtt_connection_stats,{
client_identifier = <<>> :: binary(),

View File

@@ -433,18 +433,22 @@ create_ca(CaName,Password,State,_Pid)->
CaKeyCertFileName = filename:join([CaDir,binary_to_list(CaName) ++ "_cert.pem"]),
CaConfigFileName = filename:join([CaDir,binary_to_list(CaName)++".cnf"]),
Cmd0 = io_lib:format("openssl genrsa -passout pass:~s -aes256 -out ~s 4096",[Password,CaKeyFileName]),
Cmd0 = case Password == <<>> of
false -> io_lib:format("openssl genrsa -passout pass:~s -aes256 -out ~s 4096",[Password,CaKeyFileName]);
true -> io_lib:format("openssl genrsa -out ~s 4096",[CaKeyFileName])
end,
_CommandResult0 = os:cmd(Cmd0),
_ = file:change_mode(CaKeyFileName,8#0400),
%% io:format("~p> CMD0: ~s, RESULT: ~s~n~n",[Pid,Cmd0,CommandResult0]),
Cmd1 = io_lib:format("openssl req -config ~s -batch -new -x509 -days 3000 -sha256 -extensions v3_ca -passin pass:~s -key ~s -out ~s",
[ CaConfigFileName,
Password,
CaKeyFileName,
CaKeyCertFileName ]),
%% io:format("> CMD0: ~s, RESULT: ~s~n~n",[Cmd0,CommandResult0]),
Cmd1 = case Password == <<>> of
false -> io_lib:format("openssl req -config ~s -batch -new -x509 -days 3000 -sha256 -extensions v3_ca -passin pass:~s -key ~s -out ~s",
[ CaConfigFileName, Password, CaKeyFileName, CaKeyCertFileName ]);
true -> io_lib:format("openssl req -config ~s -batch -new -x509 -days 3000 -sha256 -extensions v3_ca -key ~s -out ~s",
[ CaConfigFileName, CaKeyFileName, CaKeyCertFileName ])
end,
_CommandResult1 = os:cmd(Cmd1),
_ = file:change_mode(CaKeyCertFileName,8#0444),
%% io:format("~p> CMD1: ~s, RESULT: ~s~n~n",[Pid,Cmd1,CommandResult1]),
%% io:format("> CMD1: ~s, RESULT: ~s~n~n",[Cmd1,CommandResult1]),
ok = file:write_file( filename:join([CaDir, "index.txt"]),<<>>),
ok = file:write_file( filename:join([CaDir, "serial.txt"]),<<$0,$1>>),
@@ -550,29 +554,49 @@ create_server(CAInfo,Name,Type,State,_Pid)->
ServerCertCsr = filename:join([BaseDir,"server-" ++ binary_to_list(Name) ++ "-cert.csr"]),
ServerCertPem = filename:join([BaseDir,"server-" ++ binary_to_list(Name) ++ "-cert.pem"]),
Subject = "\"/C=CA/ST=BC/L=Vancouver/O=Arilia Wireless Inc./OU=Servers/CN=" ++ binary_to_list(Name) ++ "\"",
Cmd1 = io_lib:format("openssl req -config ~s -batch -passout pass:~s -newkey rsa:2048 -sha256 -keyout ~s -out ~s -outform PEM",
[ binary_to_list(CAInfo#ca_info.config_file_name),
binary_to_list(CAInfo#ca_info.password),
ServerKeyPem,
ServerCertCsr]),
Cmd1 = case CAInfo#ca_info.password == <<>> of
false ->
io_lib:format("openssl req -config ~s -batch -passout pass:~s -newkey rsa:2048 -sha256 -keyout ~s -out ~s -outform PEM -nodes",
[ binary_to_list(CAInfo#ca_info.config_file_name),
binary_to_list(CAInfo#ca_info.password),
ServerKeyPem,
ServerCertCsr]);
true ->
io_lib:format("openssl req -config ~s -batch -newkey rsa:2048 -sha256 -keyout ~s -out ~s -outform PEM -nodes",
[ binary_to_list(CAInfo#ca_info.config_file_name),
ServerKeyPem,
ServerCertCsr])
%% "openssl req -config ~s -batch -newkey rsa:2048 -sha256 -keyout ~s -out ~s -outform PEM -nodes"
end,
_CommandResult1 = os:cmd(Cmd1),
%% io:format("~p> CMD1: ~s, RESULT: ~s~n~n",[Pid,Cmd1,CommandResult1]),
Cmd2 = io_lib:format("openssl ca -batch -passin pass:~s -config ~s -subj ~s -keyfile ~s -cert ~s -extensions server_cert -policy policy_loose -out ~s -infiles ~s",
[ binary_to_list(CAInfo#ca_info.password),
binary_to_list(CAInfo#ca_info.config_file_name),
Subject,
binary_to_list(CAInfo#ca_info.key_file_name),
binary_to_list(CAInfo#ca_info.cert_file_name),
ServerCertPem,
ServerCertCsr]),
%% io:format("> CMD1: ~s, RESULT: ~s~n~n",[Cmd1,CommandResult1]),
Cmd2 = case CAInfo#ca_info.password == <<>> of
false -> io_lib:format("openssl ca -batch -passin pass:~s -config ~s -subj ~s -keyfile ~s -cert ~s -extensions server_cert -policy policy_loose -out ~s -infiles ~s",
[ binary_to_list(CAInfo#ca_info.password),
binary_to_list(CAInfo#ca_info.config_file_name),
Subject,
binary_to_list(CAInfo#ca_info.key_file_name),
binary_to_list(CAInfo#ca_info.cert_file_name),
ServerCertPem,
ServerCertCsr]);
true -> io_lib:format("openssl ca -batch -config ~s -subj ~s -keyfile ~s -cert ~s -extensions server_cert -policy policy_loose -out ~s -infiles ~s",
[ binary_to_list(CAInfo#ca_info.config_file_name),
Subject,
binary_to_list(CAInfo#ca_info.key_file_name),
binary_to_list(CAInfo#ca_info.cert_file_name),
ServerCertPem,
ServerCertCsr])
end,
_CommandResult2 = os:cmd(Cmd2),
%% io:format("~p> CMD2: ~s, RESULT: ~s~n~n",[Pid,Cmd2,CommandResult2]),
Cmd3 = io_lib:format("openssl rsa -passin pass:~s -in ~s -out ~s",
[ binary_to_list(CAInfo#ca_info.password),
ServerKeyPem,
ServerKeyDec]),
%% io:format("> CMD2: ~s, RESULT: ~s~n~n",[Cmd2,CommandResult2]),
Cmd3 = case CAInfo#ca_info.password == <<>> of
false ->io_lib:format("openssl rsa -passin pass:~s -in ~s -out ~s",
[ binary_to_list(CAInfo#ca_info.password), ServerKeyPem, ServerKeyDec]);
true -> io_lib:format("openssl rsa -in ~s -out ~s",
[ ServerKeyPem, ServerKeyDec])
end,
_CommandResult3 = os:cmd(Cmd3),
%% io:format("~p> CMD3: ~s, RESULT: ~s~n~n",[Pid,Cmd3,CommandResult3]),
%% io:format("> CMD3: ~s, RESULT: ~s~n~n",[Cmd3,CommandResult3]),
{ok,KeyPemData} = file:read_file(ServerKeyPem),
{ok,ServerKeyDecPemData} = file:read_file(ServerKeyDec),
@@ -586,7 +610,8 @@ create_server(CAInfo,Name,Type,State,_Pid)->
key = KeyPemData,
cert = ServerCertPemData,
decrypt = ServerKeyDecPemData,
csr = ServerCertCsrPemData
csr = ServerCertCsrPemData,
cacert = CAInfo#ca_info.cert_data
},
_ = add_record(NewServerInfo),
@@ -612,23 +637,35 @@ create_client(CAInfo,Attributes,State)->
ClientCertCsr = filename:join([BaseDir,"client-" ++ binary_to_list(Name) ++ "-cert.csr"]),
ClientCertPem = filename:join([BaseDir,"client-" ++ binary_to_list(Name) ++ "-cert.pem"]),
Subject = "\"/C=CA/ST=BC/L=Vancouver/O=Arilia Wireless Inc./OU=Clients/CN=" ++ binary_to_list(Name) ++ "\"",
Cmd1 = io_lib:format("openssl req -config ~s -batch -passout pass:~s -newkey rsa:2048 -sha256 -keyout ~s -out ~s -outform PEM -nodes",
[ CAInfo#ca_info.config_file_name, CAInfo#ca_info.password, ClientKeyPem,ClientCertCsr]),
Cmd1 = case CAInfo#ca_info.password == <<>> of
false -> io_lib:format("openssl req -config ~s -batch -passout pass:~s -newkey rsa:2048 -sha256 -keyout ~s -out ~s -outform PEM -nodes",
[ binary_to_list(CAInfo#ca_info.config_file_name), binary_to_list(CAInfo#ca_info.password), ClientKeyPem,ClientCertCsr]);
true -> io_lib:format("openssl req -config ~s -batch -newkey rsa:2048 -sha256 -keyout ~s -out ~s -outform PEM -nodes",
[ binary_to_list(CAInfo#ca_info.config_file_name), ClientKeyPem, ClientCertCsr])
end,
_CommandResult1 = os:cmd(Cmd1),
%% io:format("CMD1: ~s, RESULT: ~s~n~n",[Cmd1,CommandResult1]),
Cmd2 = io_lib:format("openssl ca -batch -passin pass:~s -config ~s -subj ~s -keyfile ~s -cert ~s -extensions usr_cert -policy policy_loose -out ~s -infiles ~s",
[ binary_to_list(CAInfo#ca_info.password),
binary_to_list(CAInfo#ca_info.config_file_name),
Subject,
binary_to_list(CAInfo#ca_info.key_file_name),
binary_to_list(CAInfo#ca_info.cert_file_name),
ClientCertPem ,
ClientCertCsr
]),
Cmd2 = case CAInfo#ca_info.password == <<>> of
false -> io_lib:format("openssl ca -batch -passin pass:~s -config ~s -subj ~s -keyfile ~s -cert ~s -extensions usr_cert -policy policy_loose -out ~s -infiles ~s",
[ binary_to_list(CAInfo#ca_info.password),
binary_to_list(CAInfo#ca_info.config_file_name),
Subject,
binary_to_list(CAInfo#ca_info.key_file_name),
binary_to_list(CAInfo#ca_info.cert_file_name),
ClientCertPem ,
ClientCertCsr
]);
true -> io_lib:format("openssl ca -batch -config ~s -subj ~s -keyfile ~s -cert ~s -extensions usr_cert -policy policy_loose -out ~s -infiles ~s",
[ binary_to_list(CAInfo#ca_info.config_file_name), Subject, binary_to_list(CAInfo#ca_info.key_file_name), binary_to_list(CAInfo#ca_info.cert_file_name),
ClientCertPem , ClientCertCsr ])
end,
_CommandResult2 = os:cmd(Cmd2),
%% io:format("CMD2: ~s, RESULT: ~s~n~n",[Cmd2,CommandResult2]),
Cmd3 = io_lib:format("openssl rsa -passin pass:~s -in ~s -out ~s",
[ binary_to_list(CAInfo#ca_info.password), ClientKeyPem, ClientKeyDec]),
Cmd3 = case CAInfo#ca_info.password == <<>> of
false -> io_lib:format("openssl rsa -passin pass:~s -in ~s -out ~s", [ binary_to_list(CAInfo#ca_info.password), ClientKeyPem, ClientKeyDec]);
true -> io_lib:format("openssl rsa -in ~s -out ~s", [ ClientKeyPem, ClientKeyDec])
end,
_CommandResult3 = os:cmd(Cmd3),
%% io:format("CMD3: ~s, RESULT: ~s~n~n",[Cmd3,CommandResult3]),
@@ -647,6 +684,7 @@ create_client(CAInfo,Attributes,State)->
key = ClientKeyPemData,
cert = ClientCertPemData,
decrypt = ClientKeyDecData,
cacert = CAInfo#ca_info.cert_data,
csr = ClientCertCsrData
},
@@ -704,6 +742,8 @@ valid_ca_name([H|T],Pos) when (((H >= $0) and (H =< $9)) or ((H >= $a) and (H =<
valid_ca_name(_,_Pos)->
false.
valid_password("")->
true;
valid_password(Password)->
valid_password(Password,1).
valid_password([],Pos) when Pos >= 8 ->

View File

@@ -11,19 +11,40 @@
-include("../include/common.hrl").
-include("../include/inventory.hrl").
-include("../include/mqtt_definitions.hrl").
%% API
-export([start/4]).
-record(client_state,{manager_pid, topics, compress, configuration, details}).
-record(client_state,{id, manager_pid, topics, compress, configuration, details}).
start(CAName,Id,Configuration,ManagerPid)->
#{ <<"broker">> := Broker, <<"compress">> := Compress, <<"port">> := Port, <<"topics">> := Topics } = Configuration,
{ok,DeviceConfiguration} = inventory:get_client(CAName,Id),
{ok,SSL}=ssl:connect(binary_to_list(Broker),list_to_integer(binary_to_list(Port)),
[ {cert,DeviceConfiguration#client_info.cert}, {key,DeviceConfiguration#client_info.key}]),
CS = #client_state{ manager_pid = ManagerPid, topics = Topics, compress = Compress , configuration = Configuration, details = DeviceConfiguration },
[
{session_tickets,auto},
{versions, ['tlsv1.2','tlsv1.3']},
{cert,DeviceConfiguration#client_info.cert},
{key,DeviceConfiguration#client_info.key},
{active,false },
binary]),
CS = #client_state{ id=Id, manager_pid = ManagerPid, topics = Topics, compress = Compress , configuration = Configuration, details = DeviceConfiguration },
run_client(SSL,CS).
run_client(SSL,CS)->
C = #mqtt_connect_variable_header{
protocol_version = ?MQTT_PROTOCOL_VERSION_3_11,
username_flag = 0,
password_flag = 0,
will_retain_flag = 0,
will_qos_flag = 0,
will_flag = 0 ,
clean_start_flag = 1,
client_identifier = CS#client_state.id,
keep_alive = 60 },
M = #mqtt_msg{ variable_header = C},
ConnectMessage = mqtt_message:encode(M),
_ = ssl:send(SSL,ConnectMessage),
ok.

View File

@@ -324,12 +324,26 @@ inner_encode( #mqtt_connect_variable_header{} = Header )->
true -> mqttlib:enc_binary(Header#mqtt_connect_variable_header.password);
false -> <<>>
end,
Payload = << (mqttlib:enc_string(Header#mqtt_connect_variable_header.client_identifier))/binary,
(set_properties_section((Header#mqtt_connect_variable_header.will_properties)))/binary,
(mqttlib:enc_string(Header#mqtt_connect_variable_header.will_topic))/binary,
(mqttlib:enc_binary(Header#mqtt_connect_variable_header.will_payload))/binary,
UserNamePayload/binary,
UserPasswordPayload/binary>>,
WillTopic = case Header#mqtt_connect_variable_header.will_flag == 1 of
true -> <<(mqttlib:enc_string(Header#mqtt_connect_variable_header.will_topic))/binary,
(mqttlib:enc_binary(Header#mqtt_connect_variable_header.will_message))/binary>>;
false -> <<>>
end,
Payload = case Header#mqtt_connect_variable_header.protocol_version of
?MQTT_PROTOCOL_VERSION_5 ->
<< (mqttlib:enc_string(Header#mqtt_connect_variable_header.client_identifier))/binary,
(set_properties_section((Header#mqtt_connect_variable_header.will_properties)))/binary,
WillTopic/binary,
(mqttlib:enc_binary(Header#mqtt_connect_variable_header.will_payload))/binary,
UserNamePayload/binary,
UserPasswordPayload/binary>>;
?MQTT_PROTOCOL_VERSION_3_11 ->
<< (mqttlib:enc_string(Header#mqtt_connect_variable_header.client_identifier))/binary,
WillTopic/binary,
(mqttlib:enc_binary(Header#mqtt_connect_variable_header.will_payload))/binary,
UserNamePayload/binary,
UserPasswordPayload/binary>>
end,
Blob = <<0:8,4:8,$M,$Q,$T,$T,(Header#mqtt_connect_variable_header.protocol_version):8,Flags/binary,(Header#mqtt_connect_variable_header.keep_alive):16,Payload/binary>>,
{?MQTT_CONNECT, 0, Blob};

View File

@@ -19,6 +19,7 @@ simple_test() ->
connection_packet_encoding_decoding_test() ->
?DBGTRC("Starting"),
PacketVariableHeader = #mqtt_connect_variable_header{
protocol_version = ?MQTT_PROTOCOL_VERSION_5,
username_flag = 1 ,
password_flag = 1,
username = <<"Stephb">>,
@@ -28,6 +29,7 @@ connection_packet_encoding_decoding_test() ->
keep_alive = 60,
client_identifier = <<"test_device_1">>,
will_topic = <<"topics/a">>,
will_message = <<>>,
clean_start_flag = 1,
will_properties = [{will_delay_interval,1000},
{payload_format_indicator,1},

View File

@@ -214,7 +214,7 @@ progress(BatchNumber,Id,SimName)->
io:format("~nSimulation ~s preparation progress: ID=~s Batch=~p~n",[binary_to_list(SimName),binary_to_list(Id),BatchNumber]).
%% Create the servers - only if they are pon automatic mode
split_build_servers(SimInfo,Notification)->
split_build_servers(SimInfo,_Notification)->
_ = generate_server(SimInfo,mqtt_server,SimInfo#simulation.mqtt_servers),
_ = generate_server(SimInfo,ovsdb_server,SimInfo#simulation.ovsdb_servers),
ok.

100
src/ssl_test.erl Normal file
View File

@@ -0,0 +1,100 @@
%%%-------------------------------------------------------------------
%%% @author stephb
%%% @copyright (C) 2020, Arilia Wireless Inc.
%%% @doc
%%%
%%% @end
%%% Created : 03. Dec 2020 11:50 a.m.
%%%-------------------------------------------------------------------
-module(ssl_test).
-author("stephb").
%% API
-export([start/0,server/0,client/0]).
-define(S_CERT,"certs/test_certs/server-mqtt-1--cert.pem").
-define(S_KEY ,"certs/test_certs/server-mqtt-1--key.pem").
-define(S_DKEY,"certs/test_certs/server-mqtt-1--key_dec.pem").
-define(C_CERT,"certs/test_certs/client-sim1-1-000032-cert.pem").
-define(C_KEY ,"certs/test_certs/client-sim1-1-000032-key.pem").
-define(C_DKEY,"certs/test_certs/client-sim1-1-000032-key_dec.pem").
-define(C_CA ,"certs/test_certs/sim1_cert.pem").
-define(PORT,11000).
start()->
_=ssl:start(),
spawn(?MODULE,server,[]),
timer:sleep(2000),
spawn(?MODULE,client,[]).
server()->
{ ok , ListenSocket } = ssl:listen(?PORT,[
%% {log_level,debug},
{session_tickets,stateless},
{mode,binary},
{versions,['tlsv1.2','tlsv1.3']},
{active,false},
{reuseaddr,true},
{certfile,?S_CERT},
{keyfile,?S_KEY}
]),
accept(ListenSocket).
accept(ListenSocket) ->
_=case ssl:transport_accept(ListenSocket) of
{ok,Socket} ->
case ssl:handshake(Socket) of
{ ok, SslSocket } ->
_=ssl:setopts(SslSocket,[{active,true}]),
server_processor_active(SslSocket),
io:format("Client is done...~n");
Error ->
io:format("Client error is done: ~p...~n",[Error]),
ssl:close(Socket)
end;
Error ->
io:format("Client error done: ~p...~n",[Error])
end,
accept(ListenSocket).
%% server_processor_passive(Socket)->
%% case ssl:recv(Socket,10) of
%% {ok,Data} ->
%% io:format("Received ~p bytes: ~p.~n",[size(Data),Data]);
%% Error ->
%% io:format("Error ~p.~n",[Error])
%% end,
%% server_processor_passive(Socket).
server_processor_active(Socket)->
receive
{ssl,Socket,Data} ->
io:format("Received ~p bytes: ~p.~n",[size(Data),Data]),
server_processor_active(Socket);
{ssl_closed,Socket} ->
io:format("Closing socket.~n");
Anything ->
io:format("Unknown message: ~p.~n",[Anything]),
server_processor_active(Socket)
end.
client()->
%% {ok,Cacerts}=file:read_file(?C_CA),
{ok,SSL}=ssl:connect("renegademac.arilia.com",?PORT,
[
%% {log_level,debug},
{session_tickets,auto},
{versions, ['tlsv1.2','tlsv1.3']},
{certfile,?C_CERT},
{keyfile,?C_KEY},
{active,false },
binary]),
send_data(SSL).
send_data(SSL)->
_ = ssl:send(SSL,<<"foo">>),
%% io:format("Sending: ~p~n",[E]),
timer:sleep(1000),
send_data(SSL).

View File

@@ -137,7 +137,7 @@ show_plan(_SimName)->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec create_ca(CAName::string())-> generic_result().
create_ca(CAName) when is_list(CAName)->
create_ca(CAName,"password").
create_ca(CAName,"").
-spec create_ca(CAName::string(),Password::string())-> generic_result().
create_ca(CAName,Password) when is_list(CAName),is_list(Password)->