Blog / · Thomas Falkner

Sage 100: Warum die Lizenzprüfung ohne TLS 1.2 scheitert

Sage 100: Warum die Lizenzprüfung ohne TLS 1.2 scheitert

Das Fehlerbild ist unspektakulär und deswegen ärgerlich. Die Sage 100 läuft seit Jahren, am Server hat niemand etwas geändert, und plötzlich meldet der zentrale Mehrbenutzerdienst, dass er die Lizenz nicht prüfen kann. Im Ereignisprotokoll steht irgendetwas von einer fehlgeschlagenen Verbindung. Der Admin pingt den Sage-Server an, kommt durch, schaut in die Firewall, findet nichts Auffälliges, und steht dann davor.

Die Ursache liegt fast immer eine Schicht tiefer, als man sie sucht: Der Dienst erreicht den Sage-Lizenz-Service durchaus, er scheitert erst an der Verschlüsselungsaushandlung. Und zwar nicht, weil Windows kein TLS 1.2 könnte, sondern weil die Anwendung gar nicht erst danach fragt.

Was der Mehrbenutzerdienst mit Lizenzen zu tun hat

Klassische Sage-100-Lizenzen waren eine lokale Angelegenheit. Eine Lizenzdatei wurde eingespielt, der Mehrbenutzerdienst verteilte die Arbeitsplätze daraus, fertig. Mit den Subskriptions-Lizenzen ist eine Online-Komponente dazugekommen. Die Berechtigung hat eine begrenzte Gültigkeit und wird in regelmäßigen Abständen beim Sage-Lizenz-Service, kurz SLS, erneuert.

Diesen Abgleich macht der zentrale Mehrbenutzerdienst. Er ist die einzige Komponente im System, die dafür nach außen telefoniert, und zwar per HTTPS an https://licensing2.services.sage.com. Kein Client, kein Applikationsserver, nur der eine Dienst auf dem einen Rechner.

Das erklärt den zeitlichen Verlauf, der die Diagnose so oft in die Irre führt. Am Tag, an dem die Voraussetzungen auf dem Server wegbrechen, passiert erst einmal gar nichts. Die vorhandene Berechtigung läuft weiter. Erst wenn der nächste Abgleich fällig wäre und wiederholt scheitert, kippt das System. Zwischen Ursache und Symptom können Tage liegen, und die Änderung, die man dann sucht, war ein Windows-Update oder eine Härtungsmaßnahme, an die längst niemand mehr denkt.

Der eigentliche Punkt: Wer entscheidet über die TLS-Version

Beim Aufbau einer TLS-Verbindung schickt der Client als Erstes ein ClientHello. Darin steht, welche Protokollversionen und welche Verschlüsselungsverfahren er anbietet. Der Server sucht sich daraus etwas aus, das er ebenfalls beherrscht, und antwortet mit seiner Wahl. Gibt es keine Schnittmenge, endet die Sache mit einem Handshake-Failure-Alert oder einem schlicht geschlossenen Socket.

Der Sage-Lizenz-Service akzeptiert nur noch TLS 1.2 und neuer. Das ist kein Sage-Sonderweg. TLS 1.0 stammt von 1999, TLS 1.1 von 2006, und beide haben eine unerfreuliche Geschichte. Der BEAST-Angriff nutzt den vorhersagbaren Initialisierungsvektor im CBC-Modus aus, Lucky Thirteen holt über Laufzeitunterschiede beim Padding Klartext heraus. Dazu kommt die Abhängigkeit von SHA-1 für die Handshake-Integrität. Der PCI-Standard hat die Abschaltung zum 30. Juni 2018 verlangt, die Browserhersteller sind 2020 nachgezogen, und seit 2021 ist die Sache mit RFC 8996 auch offiziell erledigt. Dort steht wörtlich, dass TLS 1.0 und TLS 1.1 nicht mehr verwendet werden dürfen.

Interessant wird es auf der Client-Seite. Man nimmt intuitiv an, dass ein Windows Server, der TLS 1.2 unterstützt, dieses Protokoll dann auch benutzt. Das stimmt für die TLS-Implementierung von Windows, die Microsoft offiziell Secure Channel, kurz Schannel, nennt. Es stimmt nicht für eine .NET-Framework-Anwendung, die darauf aufsetzt.

Der Kern des Problems: Das .NET Framework gibt Schannel explizit vor, welche Protokolle im ClientHello landen dürfen. Der Standardwert dieser Vorgabe war jahrelang SSL 3.0 und TLS 1.0. Windows könnte also TLS 1.2 sprechen, aber die Anwendung untersagt es ihm aktiv. Der Server auf der Gegenseite sieht ein ClientHello mit maximal TLS 1.0 und legt auf.

Ab .NET Framework 4.6 hat Microsoft die Voreinstellung geändert. Nur greift die neue Voreinstellung an einer Bedingung, die im Alltag gern übersehen wird: Sie hängt am Ziel-Framework, gegen das die Anwendung kompiliert wurde, nicht an der Version, die auf dem Server installiert ist. Eine Binärdatei, die gegen 4.5 gebaut wurde, bekommt weiterhin das alte Verhalten, auch auf einem Server mit .NET 4.8. Das ist Absicht und nennt sich Kompatibilitäts-Quirk. Microsoft beschreibt das in den bewährten Methoden für TLS mit dem .NET Framework recht deutlich, inklusive des Hinweises, dass SslProtocols.Default bis heute für SSL 3.0 und TLS 1.0 steht.

Deshalb ist der Satz „Auf dem Server ist doch .NET 4.8 installiert" kein Gegenargument. Und deshalb braucht es die Registry-Schalter.

Was die Registry-Keys tatsächlich bewirken

Die beiden Werte liegen unter den Framework-Zweigen und wirken prozessübergreifend für alle .NET-Anwendungen der jeweiligen Version.

  • SchUseStrongCrypto = 1 nimmt SSL 3.0 und TLS 1.0 aus der Standardliste heraus. Technisch übergibt .NET damit das Kennzeichen SCH_USE_STRONG_CRYPTO an Schannel, das bekannt schwache Algorithmen, Cipher Suites und Protokollversionen abschaltet. Das ist der historisch ältere Schalter und derjenige, den die Sage-Hinweise nennen.
  • SystemDefaultTlsVersions = 1 geht einen Schritt weiter und ist der sauberere Weg. Damit gibt .NET überhaupt keine Protokollliste mehr vor, sondern überlässt die Entscheidung dem Betriebssystem. Windows wählt dann nach seiner eigenen Schannel-Konfiguration. Das hat den angenehmen Nebeneffekt, dass ein künftiges TLS 1.3 ohne erneuten Eingriff funktioniert.

Beide zusammen zu setzen ist die von Microsoft dokumentierte Kombination. Sie widersprechen sich nicht, sondern greifen an unterschiedlichen Stellen der Auswahl.

Der dritte Wert betrifft eine andere Baustelle. Unter Internet Settings\WinHttp steuert DefaultSecureProtocols nicht .NET, sondern native Komponenten, die WinHTTP direkt verwenden. Setups, Update-Routinen und manche Dienste gehören dazu. Der übliche Wert 0x0AA0 ist eine Bitmaske und ergibt sich aus TLS 1.2 (0x800), TLS 1.1 (0x200), TLS 1.0 (0x080) und SSL 3.0 (0x020).

Warum ausgerechnet WOW6432Node

Der Punkt, an dem die meisten Umstellungen scheitern, ist der Registry-Zweig. Die Sage-Anleitung betont ihn zu Recht.

Auf einem 64-Bit-Windows gibt es zwei getrennte Ablagen unterhalb von HKEY_LOCAL_MACHINE\SOFTWARE. Der sichtbare Zweig gehört den 64-Bit-Prozessen. Für 32-Bit-Prozesse schaltet die WOW64-Schicht beim Öffnen von SOFTWARE unbemerkt nach SOFTWARE\WOW6432Node um. Die Anwendung bekommt davon nichts mit, sie glaubt, sie läse den normalen Pfad.

Der zentrale Mehrbenutzerdienst der Sage 100 ist ein 32-Bit-Prozess. Ein Eintrag ausschließlich im 64-Bit-Zweig geht für ihn ins Leere. Genau das ist der Grund, warum eine Umstellung scheinbar korrekt durchgeführt wurde und trotzdem nichts bringt.

Beim Setzen der Werte gilt dieselbe Mechanik. Eine 64-Bit-PowerShell muss WOW6432Node wörtlich im Pfad stehen haben. Eine 32-Bit-PowerShell landet automatisch dort, auch wenn der Pfad anders aussieht. Wer es in beiden Zweigen setzt, umgeht die Frage. Genau das tut auch die Registry-Datei weiter unten.

Was auf dem Server vorhanden sein muss

Bevor Du an der Registry drehst, sollten die Grundlagen stimmen:

  • Aktuelle Windows-Updates. TLS 1.2 ist auf älteren Serverständen nachgerüstet worden, nicht von Anfang an vorhanden gewesen.
  • .NET Framework 4.7.2 oder höher. Ab dieser Version ist das Verhalten ohnehin auf die Systemvorgabe umgestellt, was die Sache deutlich entspannter macht.
  • Visual C++ Redistributable 2017, also die Runtime-Version 14.1x beziehungsweise Toolset 141. Die aktualisierten Dienst-Binärdateien sind dagegen gelinkt.
  • Firewall-Freigabe für https://licensing2.services.sage.com auf Port 443, ausgehend vom Server des Mehrbenutzerdienstes.

Der Weg zum aktualisierten Dienst

Für die Sage 100 Version 9.0 genügt ein Live-Update auf 9.0.3.4. Dabei wird der zentrale Mehrbenutzerdienst mit aktualisiert. Die Windows-Anpassungen sind trotzdem fällig, das Live-Update fasst die Registry nicht an.

Für alle Stände vor 9.0.3.4 stellt Sage ein separates Setup bereit, das der Support auf Anfrage herausgibt. Es deckt auch die Versionen 7.1, 8.0 und 8.1 ab. Dafür gelten drei Regeln:

  • Das Setup wird ausschließlich auf dem Rechner des zentralen Mehrbenutzerdienstes installiert, nicht auf Clients und nicht auf weiteren Servern.
  • Vor dem Start müssen sich alle Anwender der Sage 100 abmelden.
  • Die Ausführung erfolgt mit Administrationsrechten.

Die TLS-1.2-Aktivierung in Windows gehört zusätzlich auf die Standort-Server und die Remote-Standortsysteme. Der Mehrbenutzerdienst ist der Auslöser, aber er ist nicht der einzige .NET-Prozess in der Landschaft, der nach außen spricht.

Die Registry-Datei

Wir haben die Werte in einer Registry-Datei zusammengefasst, die beide Framework-Versionen und beide Registry-Zweige abdeckt, dazu die WinHTTP-Einstellung. Der Kern sieht so aus:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001

Die vollständige Datei setzt dieselben Werte zusätzlich für v2.0.50727 und trägt DefaultSecureProtocols unter WinHttp ein. Sie fügt nur hinzu und entfernt nichts. Andere Werte, die in diesen Schlüsseln stehen, bleiben unangetastet, was auch ausdrücklich so sein soll.

Registry-Fix herunterladen

ZIP mit .reg-Datei und Kurzanleitung. Zusammenführen als Administrator, danach Server neu starten.

Eine Sicherung der betroffenen Schlüssel vorab ist trotzdem guter Stil. reg export auf die vier Framework-Pfade dauert eine halbe Minute.

Prüfen statt hoffen

Nach dem Eingriff will man wissen, ob es gewirkt hat, und zwar bevor am Montagmorgen vierzig Anwender vor einer Meldung sitzen. Drei Tests, die unterschiedliche Fragen beantworten.

Erstens: Kommt der Server netzwerkseitig überhaupt raus und beherrscht die Gegenstelle TLS 1.2? Der folgende Aufruf erzwingt TLS 1.2 unabhängig von den Prozess-Voreinstellungen.

$h = 'licensing2.services.sage.com'
$c = New-Object Net.Sockets.TcpClient($h, 443)
$s = New-Object Net.Security.SslStream($c.GetStream())
$s.AuthenticateAsClient($h, $null, [Net.SecurityProtocolType]::Tls12, $false)
"Protokoll: $($s.SslProtocol)"
"Zertifikat: $($s.RemoteCertificate.Subject)"
$s.Dispose(); $c.Close()

Läuft das durch, sind Firewall und Namensauflösung in Ordnung. Schau Dir dabei den Zertifikatsnamen an. Steht dort nicht Sage, sondern der Name Deiner Firewall oder Deines Proxys, hast Du eine TLS-Inspection im Weg. Dazu gleich mehr.

Zweitens: Was bietet ein .NET-Prozess von sich aus an? Derselbe Test mit SystemDefault statt Tls12 lässt die Voreinstellungen entscheiden und zeigt in $s.SslProtocol, was dabei herauskommt.

Drittens: Stehen die Werte in beiden Zweigen?

'HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319' | ForEach-Object {
    $p = Get-ItemProperty $_ -ErrorAction SilentlyContinue
    [PSCustomObject]@{
        Zweig                    = $_
        SystemDefaultTlsVersions = $p.SystemDefaultTlsVersions
        SchUseStrongCrypto       = $p.SchUseStrongCrypto
    }
} | Format-List

Ein leeres Feld beim WOW6432Node-Eintrag ist der häufigste Befund bei einer Umstellung, die angeblich schon gemacht wurde.

Stolperfallen

  • PowerShell testet sich selbst. Die Windows PowerShell 5.1 ist eine .NET-Framework-Anwendung und unterliegt denselben Voreinstellungen. Ein Invoke-WebRequest, das ohne explizit gesetztes SecurityProtocol scheitert, belegt das Problem sehr schön. Ein Invoke-WebRequest, das mit explizit gesetztem SecurityProtocol gelingt, belegt dagegen überhaupt nichts über den Sage-Dienst. Die beiden Varianten dürfen nicht durcheinandergeraten.
  • Neustart. Die Werte werden beim Prozessstart gelesen. Ein Dienstneustart reicht in der Regel, ein Serverneustart ist die sicherere Variante, weil auch die WinHTTP-Änderung greifen soll.
  • TLS-Inspection. Firewalls, die HTTPS aufbrechen, präsentieren dem Client ihr eigenes Zertifikat. Fehlt deren Aussteller im Zertifikatsspeicher des Computerkontos, scheitert die Validierung, obwohl TLS 1.2 einwandfrei ausgehandelt wurde. Das Fehlerbild ähnelt sich, die Ursache ist eine andere. Eine Ausnahme für den Lizenzhost im Proxy ist der ruhigere Weg.
  • Proxy mit Anmeldung. Der Mehrbenutzerdienst läuft unter einem Dienstkonto. Was im Browser des angemeldeten Administrators funktioniert, funktioniert für dieses Konto noch lange nicht.
  • Härtungstools. Werkzeuge wie IIS Crypto schalten Protokolle getrennt nach Server- und Client-Rolle. Es kommt vor, dass TLS 1.2 serverseitig aktiv ist und clientseitig unter SCHANNEL\Protocols\TLS 1.2\Client auf Enabled = 0 beziehungsweise DisabledByDefault = 1 steht. Dann nützt die schönste .NET-Einstellung nichts, weil Schannel das Protokoll gar nicht erst anbietet. Welche Werte dort zulässig sind, steht in den TLS-Registrierungseinstellungen für Schannel.

Der Workaround und seine Grenzen

Wenn es brennt und der Betrieb gerade steht, verschafft das Einspielen einer neuen Lizenz Luft. Die Gültigkeit beginnt von vorn, die Anwender können arbeiten. Als Lösung taugt das nicht. Der nächste fällige Abgleich läuft in denselben Fehler, und dann steht die Umstellung wieder an, nur unter mehr Zeitdruck.

Fazit

Die Aktualisierung des Mehrbenutzerdienstes auf TLS 1.2 ist für den Betrieb von Subskriptions-Lizenzen nicht optional. Sie besteht aus zwei Teilen, die beide gemacht werden müssen: Der Dienst selbst über Live-Update 9.0.3.4 oder das Sage-Setup, und die Windows-Seite über die Registry. Der eine Punkt, an dem es in der Praxis hakt, ist der Zweig WOW6432Node.

Weiterführend zum Thema TLS unter .NET gibt es eine ausführliche Seite bei Microsoft: TLS 1.2 auf Standortservern und Remotestandortsystemen aktivieren.

Wenn Du nicht sicher bist, auf welchem Stand Dein Mehrbenutzerdienst ist oder ob die Umstellung vollständig gegriffen hat, schauen wir uns das gern gemeinsam an. Passend dazu auch unser Beitrag zum Applikationsserver der Sage 100.

Unterstützung bei der TLS-Umstellung anfragen

Wie hilfreich war dieser Beitrag?

Noch keine Bewertungen.