簡體   English   中英

SslStream AuthenticateAsClient 方法獲取“由於意外的數據包格式導致握手失敗”錯誤

[英]SslStream AuthenticateAsClient method getting "The handshake failed due to an unexpected packet format" error

我們的代碼在 C# 中使用TcpClient 和 SslStream遇到錯誤The handshake failed due to an unexpected packet format. 在調用AuthenticateAsClient方法時,SMTP 服務器是smtp.office365.com ,但我們嘗試了很多方法,但都沒有。

  1. 試過: System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

  2. 試過: ssl.AuthenticateAsClient(Server, null, System.Security.Authentication.SslProtocols.Tls12, true);

  3. 嘗試了其他 AuthenticateAsClient 重載方法都不起作用。

  4. 同樣使用Microsoft Network Monitor 3.4工具,我們可以確認Client Hello握手使用 TSL1.2 協議。

有人遇到過類似的問題嗎?

以下是使用 .NET 框架 8 的控制台中的完整代碼

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string Server = "smtp-legacy.office365.com";
                //This server raise error too
                Server = "smtp.office365.com";
                int port = 587;
                //tried this, not working
                //System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
                //
                using (var tcp = new System.Net.Sockets.TcpClient())
                {
                    tcp.Connect(Server, port);

                    System.Net.Security.RemoteCertificateValidationCallback remoteCertCallback =
                        new System.Net.Security.RemoteCertificateValidationCallback((Object sender,
                               System.Security.Cryptography.X509Certificates.X509Certificate cert,
                               System.Security.Cryptography.X509Certificates.X509Chain chain,
                               System.Net.Security.SslPolicyErrors Errors) => true);

                    //System.Net.Security.SslStream ssl = 
                    //    new System.Net.Security.SslStream(tcp.GetStream(), false, remoteCertCallback, null);

                    //Try set LocalCertificateSelectionCallback
                    System.Net.Security.SslStream ssl =
                        new System.Net.Security.SslStream(tcp.GetStream(), false, remoteCertCallback, SelectLocalCertificate);

                    //Raise error: The handshake failed due to an unexpected packet format.
                    #region Try to specify the protocol, not working
                    ssl.AuthenticateAsClient(Server, null, System.Security.Authentication.SslProtocols.Tls12, true);
                    #endregion

                    #region Try to set local certificate, not working
                    //tried to set local certificate, not working
                    //X509CertificateCollection clientCertificates = GetLocalCertificates();
                    //ssl.AuthenticateAsClient(Server, clientCertificates, System.Security.Authentication.SslProtocols.Tls12, true);
                    #endregion

                    #region Default way, not working
                    //Raise error: The handshake failed due to an unexpected packet format.
                    //ssl.AuthenticateAsClient(Server);
                    #endregion


                }

            }
            //Raise error: The handshake failed due to an unexpected packet format.
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            Console.Read();

        }


        public static X509Certificate2Collection GetLocalCertificates()
        {
            X509Certificate2Collection Certificates = null;
            // Read the certificate from the store
            X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            try
            {
                store.Open(OpenFlags.ReadOnly);
                //Certificates = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName,
                //"CN=[YOUR DOMAIN]", false);
                Certificates = store.Certificates;
            }
            finally
            {
                store.Close();
            }

            return Certificates;
        }

        public static X509Certificate SelectLocalCertificate(
            object sender,
            string targetHost,
            X509CertificateCollection localCertificates,
            X509Certificate remoteCertificate,
            string[] acceptableIssuers)
        {
            if (acceptableIssuers != null &&
                acceptableIssuers.Length > 0 &&
                localCertificates != null &&
                localCertificates.Count > 0)
            {
                // Use the first certificate that is from an acceptable issuer.
                foreach (X509Certificate certificate in localCertificates)
                {
                    string issuer = certificate.Issuer;
                    if (Array.IndexOf(acceptableIssuers, issuer) != -1)
                        return certificate;
                }
            }
            if (localCertificates != null &&
                localCertificates.Count > 0)
                return localCertificates[0];

            return null;
        }

    }

最后,我們找到了解決方案,在這里發布以防萬一有人遇到同樣的問題:

所以有兩種情況:
案例1:對於TLS,需要在步驟5之后調用AuthenticateAsClient
案例2:對於SSL,需要在步驟1之后調用AuthenticateAsClient

我們的問題是我們在步驟 1 之后為 TLS 調用了AuthenticateAsClient ,正確的 position 是我們應該在Step 5之后調用AuthenticateAsClient ,在發送StartTLS之后確保服務器返回支持 StartTSL 的信息。

Step 1. 客戶端:TCP 握手/連接
(For SSL only) call AuthenticateAsClient before EHLO
步驟 2. 服務器:200 就緒
步驟 3. 客戶:EHLO
Step 4. Server: 250 StartTLS(表示支持TLS)
步驟 5. 客戶端:StartTLS(發送 StartTLS 推薦)
(For TLS only) call AuthenticateAsClient after StartTLS
步驟 6. 服務器:220 Go 頭
步驟 7. 客戶端:發送加密數據/電子郵件(已編輯)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM