2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-10 08:04:00 +00:00

10_ZWave.pm: some security modification (Forum #38587)

git-svn-id: https://svn.fhem.de/fhem/trunk@9674 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2015-10-25 18:55:42 +00:00
parent 673c37f92c
commit 12424377ef

View File

@ -15,6 +15,8 @@ sub ZWave_Parse($$@);
sub ZWave_Set($@);
sub ZWave_SetClasses($$$$);
sub ZWave_addToSendStack($$);
sub ZWave_secStart($);
sub ZWave_secEnd($);
use vars qw(%zw_func_id);
use vars qw(%zw_type6);
@ -168,7 +170,7 @@ my %zwave_class = (
get => { setpoint => "02" },
parse => { "064303(..)(..)(....)" => 'sprintf("setpointTemp:%0.1f %s %s", '.
'hex($3)/(10**int(hex($2)/32)), '.
'hex($2)&8 ? "F":"C", $1==1 ? "heating":"cooling")' } },
'hex($2)&8 ? "F":"C", hex($1)==1 ? "heating":"cooling")' } },
THERMOSTAT_FAN_MODE => { id => '44' },
THERMOSTAT_FAN_STATE => { id => '45' },
CLIMATE_CONTROL_SCHEDULE => { id => '46',
@ -376,7 +378,7 @@ my %zwave_class = (
get => { "secSupported" => 'ZWave_sec($hash, "02")' ,
"secNonce" => 'ZWave_sec($hash, "40")'},
parse => { "..9803(.*)" => 'ZWave_secSupported($hash, $1)',
"..9805(.*)" => 'ZWave_secureInit($hash, $1)', # secScheme
"..9805(.*)" => 'ZWave_secInit($hash, $1)', # secScheme
"..9807" => 'ZWave_secNetWorkKeyVerify($hash)',
"..9840" => 'ZWave_secNonceRequestReceived($hash)',
"..9880(.*)" => 'ZWave_secNonceReceived($hash, $1)',
@ -688,8 +690,8 @@ ZWave_Cmd($$@)
return "" if($ncmd && $ncmd eq "EMPTY"); # e.g. configRequestAll
}
Log3 $name, 2, "ZWave $type $name $cmd ".join(" ", @a)
if(!$zwave_quietCmds{$cmd});
Log3 $name, $zwave_quietCmds{$cmd} ? 4 : 2,
"ZWave $type $name $cmd ".join(" ", @a);
my ($baseClasses, $baseHash) = ($classes, $hash);
if($id =~ m/(..)(..)/) { # Multi-Channel, encapsulate
@ -721,11 +723,12 @@ ZWave_Cmd($$@)
my $payload=$3;
#check message here for needed encryption (SECURITY)
if (ZWave_isSecureClass($hash, $cc_cmd)) {
if(ZWave_secIsSecureClass($hash, $cc_cmd)) {
ZWave_secStart($hash);
my $interceptedMSG = $cc_cmd . $payload;
# message stored in reading, will be processed when nonce arrives
my $cmd2 = "$type $name $cmd ".join(" ", @a);
ZWave_putSecMsg($hash, $interceptedMSG, $cmd2);
ZWave_secPutMsg($hash, $interceptedMSG, $cmd2);
return ZWave_Get($hash, $name, "secNonce");
}
}
@ -762,8 +765,22 @@ ZWave_Cmd($$@)
return $val;
}
sub ZWave_Set($@) { return ZWave_Cmd("set", shift, @_); }
sub ZWave_Get($@) { return ZWave_Cmd("get", shift, @_); }
sub
ZWave_SCmd($$@)
{
my ($type, $hash, @a) = @_;
if($hash->{secInProgress} && !(@a < 2 || $a[1] eq "?")) {
my %h = ( T => $type, A => \@a );
push @{$hash->{secStack}}, \%h;
return ($type eq "get" ?
"Secure operation in progress, executing in background" : "");
}
return ZWave_Cmd($type, $hash, @a);
}
sub ZWave_Set($@) { return ZWave_SCmd("set", shift, @_); }
sub ZWave_Get($@) { return ZWave_SCmd("get", shift, @_); }
# returns supported Parameters by hrvStatus
sub
@ -1828,9 +1845,8 @@ ZWave_sensorbinaryV2Parse($$)
##############################################
# SECURITY (start)
##############################################
sub
ZWave_secureInit(@)
ZWave_secInit(@)
{
my ($hash, $param) = @_;
my $iodev = $hash->{IODev};
@ -1845,10 +1861,10 @@ ZWave_secureInit(@)
my $stTxt = ($status > int(@stTxt) ? "ERR" : $stTxt[$status-1]);
if($status == 1) {
ZWave_Set($hash, $name, "secScheme");
ZWave_Cmd("set", $hash, $name, "secScheme");
return ""; # not evaluated
} elsif($status == 2) {
ZWave_Get($hash, $name, "secNonce");
ZWave_Cmd("get", $hash, $name, "secNonce");
return undef;
} else {
Log3 $name, 5, "$name: secureInit called with invalid status";
@ -1857,7 +1873,30 @@ ZWave_secureInit(@)
}
sub
ZWave_isSecureClass($$)
ZWave_secStart($)
{
my ($hash) = @_;
return if($hash->{secInProgress});
$hash->{secInProgress} = 1;
my @empty;
$hash->{secStack} = \@empty;
}
sub
ZWave_secEnd($)
{
my ($hash) = @_;
return if(!$hash->{secInProgress});
my $secStack = $hash->{secStack};
delete $hash->{secInProgress};
delete $hash->{secStack};
foreach my $cmd (@{$secStack}) {
ZWave_SCmd($cmd->{T}, $hash, @{$cmd->{A}});
}
}
sub
ZWave_secIsSecureClass($$)
{
my ($hash, $cc_cmd) = @_;
my $name = $hash->{NAME};
@ -1946,7 +1985,7 @@ ZWave_secNonceReceived($$)
my $mynonce_hex = substr (ZWave_secCreateNonce($hash), 2, 16);
my $cryptedNetworkKeyMsg = ZWave_secNetworkkeySet($r_nonce_hex,
$mynonce_hex, $key_hex, $hash->{nodeIdHex});
ZWave_Set($hash, $name, ("secEncap", $cryptedNetworkKeyMsg));
ZWave_Cmd("set", $hash, $name, ("secEncap", $cryptedNetworkKeyMsg));
$hash->{secStatus}++;
readingsSingleUpdate($hash, "SECURITY", 'INITIALIZING (Networkkey sent)',0);
Log3 $name, 5, "$name: SECURITY initializing, networkkey sent";
@ -1957,7 +1996,7 @@ ZWave_secNonceReceived($$)
}
# if nonce is received, we should have stored a message for encryption
my $getSecMsg = ZWave_getSecMsg($hash);
my $getSecMsg = ZWave_secGetMsg($hash);
my $secMsg = ( split / /, $getSecMsg, 4 )[0];
my $type = ( split / /, $getSecMsg, 4 )[1];
my $state = ( split / /, $getSecMsg, 4 )[3];
@ -1969,10 +2008,11 @@ ZWave_secNonceReceived($$)
}
my $enc = ZWave_secEncrypt($hash, $r_nonce_hex, $secMsg);
ZWave_Set($hash, $name, ("secEncap", $enc));
ZWave_Cmd("set", $hash, $name, ("secEncap", $enc));
if ($type eq "set" && $state) {
readingsSingleUpdate($hash, "state", $state, 1);
Log3 $name, 5, "$name: type=$type, state=$state ($getSecMsg)";
ZWave_secEnd($hash);
}
return undef;
@ -1980,7 +2020,7 @@ ZWave_secNonceReceived($$)
sub
ZWave_putSecMsg ($$$)
ZWave_secPutMsg ($$$)
{
my ($hash, $s, $cmd) = @_;
my $name = $hash->{NAME};
@ -1994,7 +2034,7 @@ ZWave_putSecMsg ($$$)
}
sub
ZWave_getSecMsg ($)
ZWave_secGetMsg ($)
{
my ($hash) = @_;
my $name = $hash->{NAME};
@ -2018,7 +2058,8 @@ ZWave_secNonceRequestReceived ($)
if (!ZWave_secIsEnabled($hash)) {
return;
}
return ZWave_Set($hash, $hash->{NAME}, "sendNonce");
ZWave_secStart($hash);
return ZWave_Cmd("set", $hash, $hash->{NAME}, "sendNonce");
}
sub
@ -2045,7 +2086,7 @@ ZWave_secCreateNonce($)
{
my ($hash) = @_;
if (ZWave_secIsEnabled($hash)) {
my $nonce = ZWave_getNonce();
my $nonce = ZWave_secGetNonce();
setReadingsVal($hash, "send_nonce", $nonce, TimeNow());
return ("",'80'.$nonce);
} else {
@ -2054,7 +2095,7 @@ ZWave_secCreateNonce($)
}
sub
ZWave_getNonce()
ZWave_secGetNonce()
{
my $nonce='';
for (my $i = 0; $i <8; $i++) {
@ -2077,7 +2118,7 @@ ZWave_secNetWorkKeyVerify ($)
#Log3 $iodev, 4, "$name: NetworkKeyVerify received, SECURITY is enabled";
readingsSingleUpdate($hash, "SECURITY", 'ENABLED', 0);
Log3 $name, 3, "$name: SECURITY enabled, networkkey was verified";
ZWave_Get($hash, $name, ("secSupported"));
ZWave_Cmd("get", $hash, $name, ("secSupported"));
}
sub
@ -2105,7 +2146,7 @@ ZWave_secEncrypt($$$)
my $init_enc_key = pack 'H*', 'a' x 32;
my $init_auth_key = pack 'H*', '5' x 32;
my $s_nonce_hex = ZWave_getNonce();
my $s_nonce_hex = ZWave_secGetNonce();
my $iv = pack 'H*', $s_nonce_hex . $r_nonce_hex;
my $key = pack 'H*', AttrVal($iodev->{NAME}, "networkKey", "");
my $enc_key = ZWave_secEncryptECB($key, $init_enc_key);
@ -2149,6 +2190,7 @@ ZWave_secDecrypt($$$)
my $s_nonce_hex = ReadingsVal($name, "send_nonce", undef);
if (!$s_nonce_hex) {
Log3 $name, 1, "$name: Error, no send_nonce to decrypt message available";
ZWave_secEnd($hash);
return "";
}
@ -2163,6 +2205,7 @@ ZWave_secDecrypt($$$)
if ($data !~ m/^(................)(.*)(..)(................)$/) {
Log3 $name, 1, "$name: Error, wrong format of encrypted msg";
#return (undef, undef);
ZWave_secEnd($hash);
return "";
}
my ($r_nonce_hex, $msg_hex, $s_nonce_id_hex, $auth_code_hex) = ($1, $2, $3, $4);
@ -2219,6 +2262,7 @@ ZWave_secDecrypt($$$)
Log3 $name, 5, "$name: secDecrypt: parsing $decryptedCmd";
ZWave_Parse($iodev, $decryptedCmd, undef);
ZWave_secEnd($hash);
}
} else {
Log3 $name, 1, "$name: secDecrypt: Authentification code not verified, "
@ -2229,7 +2273,7 @@ ZWave_secDecrypt($$$)
}
if ($newnonce == 1) {
ZWave_Set($hash, $hash->{NAME}, "sendNonce");
ZWave_Cmd("set", $hash, $hash->{NAME}, "sendNonce");
}
return "";
@ -2633,7 +2677,7 @@ ZWave_Parse($$@)
if($key) {
$iodev->{secInitName} = $dh->{NAME};
Log3 $ioName, 2, "ZWAVE Starting secure init";
return ZWave_secureInit($dh);
return ZWave_secInit($dh);
} else {
Log3 $ioName,1,"No secure inclusion as $ioName has no networkKey";
readingsSingleUpdate($dh, "SECURITY",