[英]“The handshake failed due to an unexpected packet format” with SmtpClient
[英]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
,但我們嘗試了很多方法,但都沒有。
試過: System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
試過: ssl.AuthenticateAsClient(Server, null, System.Security.Authentication.SslProtocols.Tls12, true);
嘗試了其他 AuthenticateAsClient 重載方法都不起作用。
同樣使用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.