UZB1 Stick: Lizenz schaltet AES Security frei?

Begonnen von buspirat, 18 November 2016, 13:37:11

Vorheriges Thema - Nächstes Thema

buspirat

Hallo Andreas,

ich habe mir den letzten Crashlog den ich Dir per E-Mail
geschickt hatte nochmal genau angesehen: In 10_ZWave.pm
ist die "pSS:" Meldung in 10_ZWave.pm aktiv, die NONCEs sind durchnummeriert.
Zusätzlich noch der Data::Dumper() in ZWDongle_shiftSendStack().


Der Übersicht halber die relevanten Meldungen am Stück:


2016.12.01 22:24:51 1: pSS: ZWave_SENSOR_NOTIFICATION_44, ack sentset:132c0a9880cda12b7c2a4d147a25ce  omsg:ce
2016.12.01 22:24:51 1: pSS: ZWave_SENSOR_NOTIFICATION_44, ack sentset:132c0a9880ced6f55c507d1ff125cf  omsg:cf
2016.12.01 22:24:51 1: pSS: ZWave_SENSOR_NOTIFICATION_44, ack sentset:132c0a9880cffba71648715d4825d0  omsg:d0
2016.12.01 22:24:52 1: pSS: ZWave_SENSOR_NOTIFICATION_44, ack sentset:132c0a9880d0ae995d353673a325d1  omsg:d1

# Jetzt kommt der Fehler in der Kommunikation.
# -> Paket wird in ZWDongle_ProcessSendStack() entfernt:
# Hinweis: Der SendStack ist nach dem "shift" in ZWDongle_shiftSendStack() leer.

2016.12.01 22:24:54 1: DEBUG: Dumping hash in ZWDongle_shiftSendStack: $VAR1 = {
          'WaitForAck' => 2,
          'SendStack' => [
                           '011100132c0a9880d123839fb30c495f25d273'
                         ],
2016.12.01 22:24:54 1: DEBUG: SendStack after shift (txt: no response from device): $VAR1 = [];
2016.12.01 22:24:54 4: no response from device, removing 011100132c0a9880d123839fb30c495f25d273 from dongle sendstack

# debug-Dump Meldungen später
2016.12.01 22:25:34 3: ZWave_SENSOR_NOTIFICATION_44: secStart older than 6 seconds detected, secUnlock will call Zwave_secEnd
2016.12.01 22:25:34 1: HASH DUMP in secUnlock before calling secEnd(): $VAR1 = {
          'SendStack' => [
                           'sentset:132c0a9880d123839fb30c495f25d2',
                           'set:132c0a9880d24c2ec20d99ed8625d3'
                         ],


-> es gibt nie eine "pSS:" Meldung für "132c0a9880d1xxxxxxx",
   die Bearbeitung der "next" Nachricht findet evtl. direkt innerhalb
   von 00_ZWDongle.pm statt, ZWDongle_Read() kann z.B. das auslösen.

Hier ist der Code in ZWDongle_ProcessSendStack(), der die Nachricht vom Stack löscht:

    } elsif($hash->{WaitForAck} == 2 && $ts-$hash->{SendTime} >= 2) {
      ZWDongle_shiftSendStack($hash, 1, 4, "no response from device");
    }
    ...
    # SendStack ist leer (siehe debug Output) -> vorzeitiger Rücksprung.
      return if(!@{$hash->{SendStack}} ||
               $hash->{WaitForAck} ||
               !DevIo_IsOpen($hash));




Der "ZWave_processSendStack()" Code in 10_ZWave.pm sieht so aus:


  IOWrite($hash,
          $hash->{homeId}.($hash->{route}?",".$hash->{route}:""),
          "00$msg");
  $ss->[0] = "sent$type:$msg";


Ich denke hier liegt das Problem: Obwohl der SendStack
durch das "no response from device" geleert wurde,
fügen wir im SendStack an Position 0 das "sent$type:$msg" ein.


An genau die "$ss->[0] = sentXXX" Stelle werde ich einen Debug-Logger die nächsten Tage einbauen und sowohl den SendStack als auch die aktuelle $msg rausloggen.
Bei mir im Log kommt zwischen dem letzten "pSS:" und dem "Crash" noch das eine oder andere ZWDongle_Read(), da könnte im 00_ZWDongle.pm schon die nächste Nachricht bearbeitet werden.
(zumindest von meinem Halbwissen vom Code her ;))

Durch das Logging wissen wir dann, ob wir uns a) eventuell innerhalb von 00_ZWDongle.pm verlaufen und die Kontrolle erst an 10_ZWave.pm zurückgeht, wenn die Nachricht vom Stack wegen Unzustellbarkeit bereits gelöscht wurde.

oder b) wir nach dem IOWrite() keinen Rückgabewert der Funktion prüfen, ob die letzte Nachricht überhaupt sauber verschickt wurde. Legen wir dann die "sentxxx" Nachricht auf den Stack, kommt alles zum Erliegen.

VG,
Thomas

buspirat

Anbei noch ein rudimentärer Callgraph für den Zwave-Stack.
Ist sehr unvollständig und ohne Security-Teil.
Geholfen hat er dennoch beim Debugging :)

Erstellt mit "yED".

A.Harrenberg

Hi Thomas,

Ich hatte mich da auf den Ablauf der Nonce konzentriert und noch nicht so sehr auf den Stack, schön das Du dazu gekommen bist!

Zitat von: buspirat am 12 Dezember 2016, 23:57:25
Der Übersicht halber die relevanten Meldungen am Stück:
Ok, ich bin gerade nicht zu Hause am Rechner, aber das eine ist doch der Stack vom Dongle und das andere ist der Stack vom Device. Ich muss mir den Ablauf da auch noch mal in Ruhe anschauen, für mich sieht es jetzt gerade danach aus das der "shift" im Dongle-Sendstack fälschlicherweise den Stack im Device nicht korrigiert, hier müsste mMn im Device-Stack ein "next" ausgelöst werden.

Zitat von: buspirat am 12 Dezember 2016, 23:57:25
-> es gibt nie eine "pSS:" Meldung für "132c0a9880d1xxxxxxx",
   die Bearbeitung der "next" Nachricht findet evtl. direkt innerhalb
   von 00_ZWDongle.pm statt, ZWDongle_Read() kann z.B. das auslösen.
Hier kann ich Dir jetzt nicht folgen...
ZWDongle_Read() sollte mMn keinen direkten Einfluß auf die Stacks haben, außer dadurch das bei erkannten ACK die versendete Nachricht vom Dongle-Sendstack genommen wird und das ACK dann auch im Device-SendStack gemeldet wird...


Zitat von: buspirat am 12 Dezember 2016, 23:57:25
Der "ZWave_processSendStack()" Code in 10_ZWave.pm sieht so aus:


  IOWrite($hash,
          $hash->{homeId}.($hash->{route}?",".$hash->{route}:""),
          "00$msg");
  $ss->[0] = "sent$type:$msg";


Ich denke hier liegt das Problem: Obwohl der SendStack
durch das "no response from device" geleert wurde,
fügen wir im SendStack an Position 0 das "sent$type:$msg" ein.
Ist jetzt "offline" nicht so einfach das alles nachzuvollziehen. Ich muss mir das zu Hause auch noch mal in Ruhe anschauen und das mal dahingehend analysieren.
Das "sent" wird mMn gesetzt sobald der Befehl vom Controller mit dem ersten ACK bestätigt wurde. Das Problem wäre dann das nach dem Ausbleiben des ACK vom Empfänger das nicht entfernt wird..

Ich meine der normale Ablauf sieht so aus:

Nachricht liegen mit set:<msg> oder get:<msg> auf dem Stack.
Die oberste wird an den Controller geschickt, der bestätigt den Empfang mit ACK -> Kennung auf dem Stack wird in sentset: bzw. sentget: geändert.
Falls ACK vom Empfänger kommt:
    - sentset: Nachrichten werden entfernt
    - sentget: Nachrichten bekommen eine neue Kennung (habe ich gerade vergessen wie es heißt) und es wird auf den Empfang der Antwort gewartet
Falls Nachricht vom Empfänger kommt und die gleiche Klasse wir der get-Befehl hat wird es als Antwort gedeutet und auch die (umbeannte) sentget: Nachricht wird vom Stack entfernt.

Problem ist hier das die ACK von den Geräten keine CallBack-ID mehr haben und daher nicht mehr ein-eindeutig zugeordnet werden können.

Zitat von: buspirat am 12 Dezember 2016, 23:57:25
An genau die "$ss->[0] = sentXXX" Stelle werde ich einen Debug-Logger die nächsten Tage einbauen und sowohl den SendStack als auch die aktuelle $msg rausloggen.
Bei mir im Log kommt zwischen dem letzten "pSS:" und dem "Crash" noch das eine oder andere ZWDongle_Read(), da könnte im 00_ZWDongle.pm schon die nächste Nachricht bearbeitet werden.
(zumindest von meinem Halbwissen vom Code her ;))

Durch das Logging wissen wir dann, ob wir uns a) eventuell innerhalb von 00_ZWDongle.pm verlaufen und die Kontrolle erst an 10_ZWave.pm zurückgeht, wenn die Nachricht vom Stack wegen Unzustellbarkeit bereits gelöscht wurde.

oder b) wir nach dem IOWrite() keinen Rückgabewert der Funktion prüfen, ob die letzte Nachricht überhaupt sauber verschickt wurde. Legen wir dann die "sentxxx" Nachricht auf den Stack, kommt alles zum Erliegen.
Das Logging sollte auf jeden Fall helfen das einfach zu erkennen.
Ich versuche das obige in den nächsten Tagen mal gedanklich nachzuspielen, allerdings wird jetzt die freie Zeit gerade ein wenig knapp...

Gruß,
Andreas.
FB 7360, Homematic und ZWave
Support for ZWave-SECURITY

A.Harrenberg

Hi,

das hier habe ich mir mal zusammengebastelt als ich was für Security nachvollziehen musste...
Ist aber auch nur ZWave_processSendStack.

Gruß,
Andreas.
FB 7360, Homematic und ZWave
Support for ZWave-SECURITY

buspirat

Zitat von: A.Harrenberg am 13 Dezember 2016, 18:27:35
für mich sieht es jetzt gerade danach aus das der "shift" im Dongle-Sendstack fälschlicherweise den Stack im Device nicht korrigiert, hier müsste mMn im Device-Stack ein "next" ausgelöst werden.
Treffer! :)

Im aktuellen Debug Log sieht man es deutlich: Der Dongle-Stack entfernt die Nachricht wegen "no response from device" in ZWDongle_ProcessSendStack(), im Device-Stack bleibt die Nachricht liegen. Aktuelle Logdatei per E-Mail.

Deine Erklärung hat mir geholfen, daß sofort nachzuvollziehen. Irgendwie bin ich davon ausgegangen, daß es nur einen globalen SendStack gibt. Ist natürlich wieder mal Käse, es gibt den Stack vom Dongle und den pro Device.

Ich schaue mir jetzt die Timeout-Timer-Logik im Device-Stack an. Soweit ich mich erinnere war der jedoch nicht aktiv, da es sich um ein Wakeup-Device handelt.

Dein Flowchart werde ich mir auch ansehen. Mit was hast Du denn das erstellt?

Viele Grüße
Thomas

A.Harrenberg

Hi Thomas,

Zitat von: buspirat am 13 Dezember 2016, 21:31:19
Im aktuellen Debug Log sieht man es deutlich: Der Dongle-Stack entfernt die Nachricht wegen "no response from device" in ZWDongle_ProcessSendStack(), im Device-Stack bleibt die Nachricht liegen. Aktuelle Logdatei per E-Mail.
habe mir den Code eben auch noch mal angeschaut und wie jedes mal auf's neue verstehe ich ihn nicht. >:(
Fängt bei mir immer damit das ich darüber stolper das man processSendStack mit "next" aufruft aber da gar keine direkte Aktion mit verknüpft ist...
Da kann ich aber frühestens am Freitag noch mal reinschauen.

Zitat von: buspirat am 13 Dezember 2016, 21:31:19
Ich schaue mir jetzt die Timeout-Timer-Logik im Device-Stack an. Soweit ich mich erinnere war der jedoch nicht aktiv, da es sich um ein Wakeup-Device handelt.
An der Stelle war ich eben auch mal, da gibt es nämlich einen Kommentar im Code der ungefähr "warten bis der retry-counter die msg vom Stack entfernt" lautet. Ich will nicht ausschliessen das hier ohne den Timer genau diese Aktion fehlschlägt bzw. gar nicht passieren kann...

Ich schaue mir aber auch noch mal die Timer aus Security an, nicht das ich dusseligerweise irgendwie den gleichen hash nutze und dann bei einem RemoveTimer beide Timer gelöscht werden. Denke ich aber nicht, das hätte sicherlich viel mehr auswirkungen auf das system.

Zitat von: buspirat am 13 Dezember 2016, 21:31:19
Dein Flowchart werde ich mir auch ansehen. Mit was hast Du denn das erstellt?
XMind, werde mir yED aber auch mal ansehen.

Gruß,
Andreas.
FB 7360, Homematic und ZWave
Support for ZWave-SECURITY

buspirat

Zitat von: A.Harrenberg am 13 Dezember 2016, 18:27:35
für mich sieht es jetzt gerade danach aus das der "shift" im Dongle-Sendstack fälschlicherweise den Stack im Device nicht korrigiert, hier müsste mMn im Device-Stack ein "next" ausgelöst werden.
die Frage ist hier wie man das "next" vom Dongle beim richtigen Device auslöst: Schickt man eine spezielle Message von ZWDongle_ProcessSendStack() via ZWDongle_Parse() vom Dongle zum Device? Oder Dispatch() direkt aufrufen?

Der Aufräum-Code wird benötigt für
      ZWDongle_shiftSendStack($hash, 1, 4, "no response from device");
und
    ZWDongle_shiftSendStack($hash, 1, 1, "ERROR: max send retries reached");

in 00_ZWDongle.pm:ZWDongle_ProcessSendStack().


@rudolfkoenig: Hast Du eine Idee zur Architektur?

Hintergrund: Da es ein Wakeup-Device ist wird in 10_ZWave.pm kein Timer gesetzt.

VG,
Thomas

buspirat

Zitat von: A.Harrenberg am 13 Dezember 2016, 22:25:48
Da kann ich aber frühestens am Freitag noch mal reinschauen.
An der Stelle war ich eben auch mal, da gibt es nämlich einen Kommentar im Code der ungefähr "warten bis der retry-counter die msg vom Stack entfernt" lautet. Ich will nicht ausschliessen das hier ohne den Timer genau diese Aktion fehlschlägt bzw. gar nicht passieren kann...
jetzt haben sich unsere Antworten überschnitten :)

Der Timer wird sehr wahrscheinlich nicht gesetzt, da es ein Wakeup-Device ist. Es gibt bisher keinen Mechanismus, daß der Dongle den Device-Stack explizit benachrichtigt, wenn er eine Nachricht verwirft. Zumindest konnte ich keine entdecken.

Das gleiche Fehlverhalten sollten auch bei einem MaxSendTries auftreten, da der ZME Stick keine extra Message für den nicht erfolgten Versand generiert bzw. auch nicht wissen kann, wieviele Versuche FHEM überhaupt unternimmt. Sprich wenn da kein gültiges NO_ACK zurück kommt, dann bleibt der Device-Stack vermutlich auch stecken.

Ein explizites Notify vom Dongle-Stack zum Device-Stack ist vermutlich besser als alles über Timer zu lösen, deswegen auch meine Anfrage an den großen Meister ;)

rudolfkoenig

Zitat@rudolfkoenig: Hast Du eine Idee zur Architektur?
Sollte ich haben, bis auf das, was ich verdraengt habe.
Fuer Security muss ich aber auf Andreas verweisen, das habe ich immer noch nicht verinnerlicht.

Kommunikation von ZWDongle zu ZWave muss ueber Dispatch laufen, damit andere Module wie FHEM2FHEM/RFR/STACKABLE_CC/usw. sich zwischenhaengen koennen. In diesem Fall wuerde ich eine spezielle Nachricht mit dem passenden Callbackid oder nodeId schicken. Das muss im ZWave_Parse rechtzeitig abgefragt werden.

buspirat

Zitat von: rudolfkoenig am 14 Dezember 2016, 08:16:25
Kommunikation von ZWDongle zu ZWave muss ueber Dispatch laufen, damit andere Module wie FHEM2FHEM/RFR/STACKABLE_CC/usw. sich zwischenhaengen koennen. In diesem Fall wuerde ich eine spezielle Nachricht mit dem passenden Callbackid oder nodeId schicken. Das muss im ZWave_Parse rechtzeitig abgefragt werden.

eventuell könnte man die bestehende Nachricht auf dem Dongle-Stack nehmen und in eine NO_ACK-Nachricht umbauen?
Checksumme und Co müsste natürlich angepasst werden. Oder ist das zu fragil und lieber eine neue Nachricht erzeugen?
Die bestehnde Nachricht hätte den Charme, daß die NodeID und Co schon passt.

A.Harrenberg

Hi Rudi,
Zitat von: rudolfkoenig am 14 Dezember 2016, 08:16:25
Sollte ich haben, bis auf das, was ich verdraengt habe.
Fuer Security muss ich aber auf Andreas verweisen, das habe ich immer noch nicht verinnerlicht.
Security ist doch "transparent" implementiert ,-)
Nee, an der Stelle mit den verschiedenen Stacks gibt es eigentlich nur die Besonderheit das auch wenn es ein WU-Gerät ist und noch keine WUN empfangen wurde bereits trotzdem ein NONCE-Request vom Geräte kommen kann. Die Antwort darauf, also das versenden der NONCE wird dann am WU-Stack vorbei direkt per addtosendstack auf den normalen Stack gelegt. Ab da sollte im Stack nichts mehr besonderes für Security sein.

An einer Stelle gibt es noch ein wenig Code damit fehlgeschlagene Transmit während Security auch den Befehl vom Security-Stack entfernen, das hat aber keinen Einfluß auf die "normalen" Stacks.

Zitat von: rudolfkoenig am 14 Dezember 2016, 08:16:25
Kommunikation von ZWDongle zu ZWave muss ueber Dispatch laufen, damit andere Module wie FHEM2FHEM/RFR/STACKABLE_CC/usw. sich zwischenhaengen koennen. In diesem Fall wuerde ich eine spezielle Nachricht mit dem passenden Callbackid oder nodeId schicken. Das muss im ZWave_Parse rechtzeitig abgefragt werden.
Ich wäre auch dafür an der Stelle eine besondere Nachricht zu generieren die man in ZWave dann explizit abfragen kann anstelled das man hier eine NO_ACK Bedingung erzeugt.

Ist aber interessant das dies alles bisher nicht wirklich aufgefallen ist. Zeugt eigentlich davon das die Übertragung an sich recht stabil und robust ist.

Wenn wir das mit eine solchen Nachricht und entsprechendem Stackeingriff in processSendStack hinbekommen dann sollte das zusammen mit der Änderung das mehr als eine NONCE gleichzeitig aktiv sein kann eine deutliche Robustheitssteigerung bewirken.

Um doppelte (oder dreifache) Arbeit zu vermeiden, wer kümmert sich denn um die Generierung einer solchen Nachricht und die Änderungen im ZWave-code um das auf den Stack anzuwenden?

Gruß,
Andreas.
FB 7360, Homematic und ZWave
Support for ZWave-SECURITY

buspirat

Zitat von: A.Harrenberg am 14 Dezember 2016, 11:25:05
Um doppelte (oder dreifache) Arbeit zu vermeiden, wer kümmert sich denn um die Generierung einer solchen Nachricht und die Änderungen im ZWave-code um das auf den Stack anzuwenden?
ich kann die Änderung zumindest testen :) Manchmal dauert es fünf Minuten bis der Fehler auftritt, manchmal zwanzig Minuten wild mit dem Magneten vom Fenstersensors rumwedeln. Die eigentliche Codeänderung traue ich mir bei meinem halbwissen über Z-Wave und FHEM noch nicht zu.

Mein FHEM verwalte ich mittlerweile lokal via git, also kann ich jederzeit Änderungen reinnehmen und z.B. problemlos meine Debug-Meldungen wieder obendrüber stülpen. Auschecken aus einer SVN-Branch wäre auch kein Problem.

VG,
Thomas

buspirat

Hi Andreas,

Zitat von: A.Harrenberg am 14 Dezember 2016, 11:25:05
... mit der Änderung das mehr als eine NONCE gleichzeitig aktiv sein kann eine deutliche Robustheitssteigerung bewirken.
soll ich den letzten Code von Dir noch versuchen zu quälen oder sollen wir erst abwarten bis der Fix für das ursprüngliche Problem verfügbar ist und dann die NONCE-Änderung auf Herz und Nieren prüfen?

VG,
Thomas

A.Harrenberg

Hi Thomas,
Zitat von: buspirat am 14 Dezember 2016, 22:21:24
soll ich den letzten Code von Dir noch versuchen zu quälen oder sollen wir erst abwarten bis der Fix für das ursprüngliche Problem verfügbar ist und dann die NONCE-Änderung auf Herz und Nieren prüfen?
ja bitte, aber dazu dann die nochmals korrigierte 10_ZWave.pm von hier nehmen oder einfach in der Funktion ZWave_secRetrieveNonce in Zeile 3624 die Kommentierung vor dem "delete($hash->{secNonce}{$s_nonce_id_hex});" entfernen.
Die Probleme sind ja voneinander getrennt, auch wenn das dauernde asynchrone Senden der nonce das andere Problem durch den erhöhten Traffic wahrscheinlich eher hervorruft.

Gruß,
Andreas.
FB 7360, Homematic und ZWave
Support for ZWave-SECURITY

buspirat

Hi Andreas,

Zitat von: A.Harrenberg am 15 Dezember 2016, 07:02:06
Hi Thomas,ja bitte, aber dazu dann die nochmals korrigierte 10_ZWave.pm
habe mir die Code-Änderungen im Detail durchgesehen, gefallen mir gut.

Einzig zu diesem Code habe ich einen Kommentar:

sub ZWave_secCreateNonce()
+    do {
+      $nonce = ZWave_secGetNonce();
+      $nonce_id = substr($nonce, 0, 2);
+    } until (!$hash->{secNonce}{$nonce_id});


wenn ein Angreifer / schlechtes Device es schafft innerhalb der zehn Sekunden bis zum Aufräumen mehr NONCES abzufragen als die zweitstellige ID-Reservierung hergibt, dann verfängt sich FHEM in einer Endlosschleife. Da sollte auf jeden Fall einen Abbruch-Bedingung rein, z.B. wenn mehr als 255 NONCES durchprobiert wurden. Oder lass es 1024 sein, sollte im realen Betrieb nie auftreten.

Werde jetzt den Code testen :)

VG,
Thomas