我们的代码在TcpClient和SslStream中使用C#,在调用AuthenticateAsClient
方法时遇到一个错误The handshake failed due to an unexpected packet format.
,SMTP服务器是smtp.office365.com
,我们尝试了许多方法,但都无法工作。
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ssl.AuthenticateAsClient(Server, null, System.Security.Authentication.SslProtocols.Tls12, true);
Client Hello
握手。有人遇到过类似的问题吗?
下面是使用.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;
}
}
发布于 2021-12-10 09:50:19
最后,我们找到了解决方案,在这里发布,以防任何人有同样的问题:
因此有两种情况:
案例1:用于TLS,需要在步骤5之后调用AuthenticateAsClient
。
案例2:用于SSL,需要在步骤1之后调用AuthenticateAsClient
。
我们的问题是,我们在步骤1之后调用了AuthenticateAsClient
,正确的位置是,我们应该在发送StartTLS
之后调用AuthenticateAsClient
,在发送StartTLS
之后,确保服务器返回支持StartTSL的信息。
步骤1.客户端: TCP握手/连接
(For SSL only) call AuthenticateAsClient before EHLO
步骤2.服务器: 200就绪
第三步客户:埃洛
步骤4.服务器:250个StartTLS(means support TLS)
步骤5. Client: StartTLS (发送StartTLS推荐)
(For TLS only) call AuthenticateAsClient after StartTLS
步骤6.服务器: 220 Go Head
步骤7.客户端:用加密发送数据/电子邮件(编辑)
https://stackoverflow.com/questions/70120066
复制相似问题