From 5c69126dad9a554e9d30729edab63f66863c9c9e Mon Sep 17 00:00:00 2001
From: rudolfkoenig <>
Date: Wed, 19 Feb 2020 16:59:03 +0000
Subject: [PATCH] #01_FHEMWEB.pm: stricter check for websocket & auto SSL cert
(Forum #108536)
git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@21230 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
FHEM/00_MQTT2_SERVER.pm | 4 ++--
FHEM/01_FHEMWEB.pm | 16 ++++++++++++----
FHEM/98_telnet.pm | 13 ++++++++-----
FHEM/TcpServerUtils.pm | 42 +++++++++++++++++++++++++++++++++++------
4 files changed, 58 insertions(+), 17 deletions(-)
diff --git a/FHEM/00_MQTT2_SERVER.pm b/FHEM/00_MQTT2_SERVER.pm
index 6202a7b06..947395d27 100644
--- a/FHEM/00_MQTT2_SERVER.pm
+++ b/FHEM/00_MQTT2_SERVER.pm
@@ -137,7 +137,7 @@ MQTT2_SERVER_Attr(@)
my ($type, $devName, $attrName, @param) = @_;
my $hash = $defs{$devName};
if($type eq "set" && $attrName eq "SSL") {
- TcpServer_SetSSL($hash);
+ InternalTimer(1, "TcpServer_SetSSL", $hash, 0); # Wait for sslCertPrefix
}
return undef;
}
@@ -660,7 +660,7 @@ MQTT2_SERVER_ReadDebug($$)
SSL
- Enable SSL (i.e. TLS)
+ Enable SSL (i.e. TLS).
sslVersion
diff --git a/FHEM/01_FHEMWEB.pm b/FHEM/01_FHEMWEB.pm
index 0b3f36885..6eedf2fce 100644
--- a/FHEM/01_FHEMWEB.pm
+++ b/FHEM/01_FHEMWEB.pm
@@ -522,7 +522,9 @@ FW_Read($$)
"&fwcsrf=".$defs{$FW_wname}{CSRFTOKEN} : "");
if($FW_use{sha} && $method eq 'GET' &&
- $FW_httpheader{Connection} && $FW_httpheader{Connection} =~ /Upgrade/i) {
+ $FW_httpheader{Connection} && $FW_httpheader{Connection} =~ /Upgrade/i &&
+ $FW_httpheader{Upgrade} && $FW_httpheader{Upgrade} =~ /websocket/i &&
+ $FW_httpheader{'Sec-WebSocket-Key'}) {
my $shastr = Digest::SHA::sha1_base64($FW_httpheader{'Sec-WebSocket-Key'}.
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
@@ -2699,7 +2701,7 @@ FW_Attr(@)
my $retMsg;
if($type eq "set" && $attrName eq "HTTPS" && $param[0]) {
- TcpServer_SetSSL($hash);
+ InternalTimer(1, "TcpServer_SetSSL", $hash, 0); # Wait for sslCertPrefix
}
if($type eq "set") { # Converting styles
@@ -3844,8 +3846,12 @@ FW_show($$)
mkdir certs
cd certs
- openssl req -new -x509 -nodes -out server-cert.pem -days 3650 -keyout server-key.pem
+ openssl req -new -x509 -nodes -out server-cert.pem -days 3650
+ -keyout server-key.pem
+ These commands are automatically executed if there is no certificate.
+ Because of this automatic execution, the attribute sslCertPrefix should
+ be set, if necessary, before this attribute.
@@ -4585,7 +4591,9 @@ FW_show($$)
openssl req -new -x509 -nodes -out server-cert.pem -days 3650 -keyout
server-key.pem
-
+ Diese Befehle werden beim Setzen des Attributes automatisch
+ ausgefürht, falls kein Zertifikat gefunden wurde. Deswegen, falls
+ nötig, sslCertPrefix vorher setzen.
diff --git a/FHEM/98_telnet.pm b/FHEM/98_telnet.pm
index 20c3a75fd..0cbb396ec 100644
--- a/FHEM/98_telnet.pm
+++ b/FHEM/98_telnet.pm
@@ -317,11 +317,14 @@ telnet_Attr(@)
my $hash = $defs{$devName};
if($type eq "set" && $attrName eq "SSL") {
- TcpServer_SetSSL($hash);
- if($hash->{CD}) {
- my $ret = IO::Socket::SSL->start_SSL($hash->{CD});
- Log3 $devName, 1, "$hash->{NAME} start_SSL: $ret" if($ret);
- }
+ InternalTimer(1, sub($) { # Wait for sslCertPrefix
+ my ($hash) = @_;
+ TcpServer_SetSSL($hash);
+ if($hash->{CD}) {
+ my $ret = IO::Socket::SSL->start_SSL($hash->{CD});
+ Log3 $devName, 1, "$hash->{NAME} start_SSL: $ret" if($ret);
+ }
+ }, $hash, 0); # Wait for sslCertPrefix
}
if(($attrName eq "allowedCommands" ||
diff --git a/FHEM/TcpServerUtils.pm b/FHEM/TcpServerUtils.pm
index 275e507d0..d2e967b3d 100644
--- a/FHEM/TcpServerUtils.pm
+++ b/FHEM/TcpServerUtils.pm
@@ -131,10 +131,15 @@ TcpServer_Accept($$)
$err = "" if(!$err);
$err .= " ".($SSL_ERROR ? $SSL_ERROR : IO::Socket::SSL::errstr());
my $errLevel = ($err =~ m/error:14094416:SSL/ ? 5 : 1); # 61511
- Log3 $name, $errLevel, "$type SSL/HTTPS error: $err (peer: $caddr)"
- if($err !~ m/error:00000000:lib.0.:func.0.:reason.0./); #Forum 56364
- close($clientinfo[0]);
- return undef;
+
+ if($err =~ m/http request/) { # HTTP on HTTPS.
+ Log3 $name, $errLevel, "HTTP connect to HTTP socket (peer: $caddr)";
+ } else {
+ Log3 $name, $errLevel, "$type SSL/HTTPS error: $err (peer: $caddr)"
+ if($err !~ m/error:00000000:lib.0.:func.0.:reason.0./); #Forum 56364
+ close($clientinfo[0]);
+ return undef;
+ }
}
}
@@ -170,9 +175,34 @@ TcpServer_SetSSL($)
if($@) {
Log3 $hash, 1, $@;
Log3 $hash, 1, "Can't load IO::Socket::SSL, falling back to HTTP";
- } else {
- $hash->{SSL} = 1;
+ return;
}
+
+ my $name = $hash->{NAME};
+ my $cp = AttrVal($name, "sslCertPrefix", "certs/server-");
+ if(! -r "${cp}key.pem") {
+
+ Log 1, "$name: Server certificate missing, trying to create one";
+ if($cp =~ m,^(.*)/(.*?), && ! -d $1 && !mkdir($1)) {
+ Log 1, "$name: failed to create $1: $!, falling back to HTTP";
+ return;
+ }
+
+ if(!open(FH,">certreq.txt")) {
+ Log 1, "$name: failed to create certreq.txt: $!, falling back to HTTP";
+ return;
+ }
+ print FH "[ req ]\nprompt = no\ndistinguished_name = dn\n\n".
+ "[ dn ]\nC = DE\nO = FHEM\nCN = home.localhost\n\n";
+ close(FH);
+
+ my $cmd = "openssl req -new -x509 -days 3650 -nodes -newkey rsa:2048 ".
+ "-config certreq.txt -out ${cp}cert.pm -keyout ${cp}key.pem";
+ Log 1, "Executing $cmd";
+ `$cmd`;
+ unlink("certreq.txt");
+ }
+ $hash->{SSL} = 1;
}