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($$) + 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; }