From 661e0cb5986c53c9b659328d835852765c71e2d8 Mon Sep 17 00:00:00 2001 From: PointStar Date: Mon, 11 May 2026 16:15:42 +0300 Subject: [PATCH] =?UTF-8?q?fix(tls):=20enable=20TLS=201.2/1.3=20on=20AddIn?= =?UTF-8?q?=20startup=20=E2=80=94=20fix=20SecureChannelFailure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Symptom: "Could not create SSL/TLS secure channel" on every CRM request (GlobalSearch, MatchingService, TestConnection). TCP and DNS succeed fine — the failure is at the schannel handshake stage. Root cause: .NET Framework 4.8 inherits ServicePointManager.SecurityProtocol from the host process. In Outlook 2019/M365 that ends up as SSL3/Tls1 which modern HTTPS servers reject. Fix: in AddInHost ctor, OR Tls12 + Tls13 into SecurityProtocol before any HttpClient is created. Tls13 (value 12288) is wrapped in try/catch for pre-Win10-1809 systems. Also surface WebExceptionStatus values in the Settings "Test connection" dialog (SecureChannelFailure / TrustFailure / NameResolutionFailure / ConnectFailure / Timeout) so future schannel issues report a clear Hebrew explanation instead of "One or more errors occurred". Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ViewModels/SettingsViewModel.cs | 16 ++++++++++++ src/OutlookAddin/Services/AddInHost.cs | 25 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/OutlookAddin.UI/ViewModels/SettingsViewModel.cs b/src/OutlookAddin.UI/ViewModels/SettingsViewModel.cs index caba8f8..b99a9e4 100644 --- a/src/OutlookAddin.UI/ViewModels/SettingsViewModel.cs +++ b/src/OutlookAddin.UI/ViewModels/SettingsViewModel.cs @@ -161,6 +161,22 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels current = current.InnerException; } + if (current is System.Net.WebException web) + { + switch (web.Status) + { + case System.Net.WebExceptionStatus.SecureChannelFailure: + return "כשל TLS — לא הצלחתי ליצור ערוץ מאובטח. ייתכן שהשרת דורש TLS 1.2/1.3 שאינו מופעל ב-.NET Framework. נסה לסגור ולפתוח Outlook מחדש; אם הבעיה חוזרת, פנה לאדמין."; + case System.Net.WebExceptionStatus.TrustFailure: + return "אישור ה-TLS של השרת לא נסמך. ייתכן שצריך להתקין את ה-CA של השרת ב-Trusted Root."; + case System.Net.WebExceptionStatus.NameResolutionFailure: + return $"השרת {target.Host} לא נמצא ב-DNS. ודא שהכתובת נכונה."; + case System.Net.WebExceptionStatus.ConnectFailure: + return $"החיבור ל-{target.Host}:{target.Port} נכשל. ודא שהשרת רץ ושאין חסימה ברשת."; + case System.Net.WebExceptionStatus.Timeout: + return "החיבור פג זמן. השרת אולי לא מגיב."; + } + } if (current is System.Net.Sockets.SocketException sock) { switch (sock.SocketErrorCode) diff --git a/src/OutlookAddin/Services/AddInHost.cs b/src/OutlookAddin/Services/AddInHost.cs index b9d9658..665a8c6 100644 --- a/src/OutlookAddin/Services/AddInHost.cs +++ b/src/OutlookAddin/Services/AddInHost.cs @@ -52,6 +52,14 @@ namespace OutlookAddin.Services public AddInHost(Outlook.Application outlookApp) { _outlookApp = outlookApp ?? throw new ArgumentNullException(nameof(outlookApp)); + + // .NET Framework 4.8 defaults to SystemDefault for TLS negotiation, + // which in Outlook's host process can end up as SSL3/TLS1.0 and trip + // "Could not create SSL/TLS secure channel" on modern EspoCRM servers. + // Force TLS 1.2 (always present on Win10+) and try TLS 1.3 (Win10 + // 1809+ only — wrap in try/catch for older Windows). + EnableModernTls(); + Logger = LoggerFactory.Init(); Logger.Information("AddInHost starting up"); @@ -70,6 +78,23 @@ namespace OutlookAddin.Services HookItemSend(); } + private static void EnableModernTls() + { + try + { + System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12; + } + catch (NotSupportedException) { /* extremely old Windows — ignore */ } + + try + { + // Tls13 enum is present in .NET Framework 4.8, but the OS schannel + // only honours it on Windows 10 1809+ / Server 2022+. + System.Net.ServicePointManager.SecurityProtocol |= (System.Net.SecurityProtocolType)12288; + } + catch (NotSupportedException) { /* older Windows — TLS 1.2 only is fine */ } + } + private void InitializeSentItemsWatcher() { try