提问人:Jon Cage 提问时间:8/21/2023 最后编辑:Jon Cage 更新时间:8/22/2023 访问量:166
为什么我的 SMTP TLS v1.3 连接尝试导致 Win32Exception:无法联系本地安全机构
Why does my SMTP TLS v1.3 connection attempt result in Win32Exception: The Local Security Authority cannot be contacted
问:
我有一些诊断代码(.net 框架 v4.8 和 C++/CLI 代码,如果您想知道奇怪的语法),它会通过电子邮件报告错误,并且我一直在努力确保它支持 TLS 1.3:
System::Net::ServicePointManager::SecurityProtocol = System::Net::SecurityProtocolType::Tls13;
System::Net::Mail::SmtpClient^ smtpClient = gcnew System::Net::Mail::SmtpClient(emailServer, port);
smtpClient->UseDefaultCredentials = false;
System::Net::NetworkCredential ^_NetworkCredential = gcnew System::Net::NetworkCredential(loginName, loginPassword);
smtpClient->Credentials = _NetworkCredential;
smtpClient->EnableSsl = true;
smtpClient->Send(mailMessage);
当我连接到gmail SMTP服务器(与基于linux的测试服务器相同)时,我得到以下信息:
Authentication error. Please check that the email certificate and system date / time are correct : System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> System.ComponentModel.Win32Exception: The Local Security Authority cannot be contacted
--- End of inner exception stack trace ---
at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.TlsStream.CallProcessAuthentication(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.Mail.SmtpConnection.Flush()
at System.Net.Mail.ReadLinesCommand.Send(SmtpConnection conn)
at System.Net.Mail.EHelloCommand.Send(SmtpConnection conn, String domain)
at System.Net.Mail.SmtpConnection.GetConnection(ServicePoint servicePoint)
at System.Net.Mail.SmtpTransport.GetConnection(ServicePoint servicePoint)
at System.Net.Mail.SmtpClient.GetConnection()
at System.Net.Mail.SmtpClient.Send(MailMessage message)
--- End of inner exception stack trace ---
at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest, Boolean renegotiation)
at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.TlsStream.CallProcessAuthentication(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.Mail.SmtpConnection.Flush()
at System.Net.Mail.ReadLinesCommand.Send(SmtpConnection conn)
at System.Net.Mail.EHelloCommand.Send(SmtpConnection conn, String domain)
at System.Net.Mail.SmtpConnection.GetConnection(ServicePoint servicePoint)
at System.Net.Mail.SmtpTransport.GetConnection(ServicePoint servicePoint)
at System.Net.Mail.SmtpClient.GetConnection()
at System.Net.Mail.SmtpClient.Send(MailMessage message)
我必须按照以下指南在我的 Win10 机器上手动启用 TLS 1.3 支持: https://www.asustor.com/en/knowledge/detail/?id=&group_id=1011
是否有可能我错过了一个步骤,或者我的 Windows 计算机有问题,会阻止 TLS 1.3 SMTP 连接?
编辑
澄清一下,在我的 Windows 10 机器上,如果我不进行任何更改,如果我检查它,即使 Tls 1.1 和 Tls 1.2 已设置为启用并且默认情况下在注册表中未禁用,也会报告。我可能在这里遗漏了一个步骤,但在我的开发机器和我尝试部署代码的机器上似乎都是这种情况。System::Net::ServicePointManager::SecurityProtocol
Ssl3 | Tls
答:
我在研究中发现的一切都指向@Panagiotis在原始问题的评论中指出的内容,这表明我们应该删除硬编码值,但这样做会导致类在我的机器上使用 TLS 1.0。System::Net::Mail::SmtpClient
尽管这与Microsoft的建议背道而驰,但我发现可靠地鼓励类使用 >TLS 1.0 的唯一方法是设置:System::Net::Mail::SmtpClient
System::Net::ServicePointManager::SecurityProtocol = System::Net::SecurityProtocolType::Tls13 | System::Net::SecurityProtocolType::Tls12 | System::Net::SecurityProtocolType::Tls11 | System::Net::SecurityProtocolType::Tls;
...根据我的测试(目前我的 Windows 1.2 机器上的 TLS 10)客户端和服务器支持的内容,它能做到最好。
评论
真正的解决方案是不使用 SmtpClient。该类自己的文档警告说它已经过时了:
重要
建议不要使用 SmtpClient 类进行新开发,因为 SmtpClient 不支持许多新式协议。请改用 MailKit 或其他库。有关详细信息,请参阅不应在 GitHub 上使用 SmtpClient。
提议的替代方案 MailKit 非常受欢迎,在 NuGet 中的下载量超过 80M。默认情况下,它不适用于低于 TLS 1.2 的任何内容。从常见问题解答中:
MailKit 试图跟上最新的安全建议,因此不断从默认配置中删除不再被视为安全的旧 SSL 和 TLS 协议。这通常意味着 MailKit 的 SMTP、POP3 和 IMAP 客户端将无法连接到仍在使用较旧 SSL 和 TLS 协议的服务器。目前默认不支持的SSL和TLS协议有:SSL v2.0、SSL v3.0、TLS v1.0和TLS v1.1。
MailKit 的 SmtpClient 类具有类似于 的 API。NET的SmtpClient,具有许多额外的功能。这意味着它几乎(但不完全)是一个直接的替代品。
public static void SendMessages (IList<MimeMessage> messages)
{
using (var client = new SmtpClient ()) {
client.Connect ("smtp.myserver.com", 465, SecureSocketOptions.SslOnConnect);
client.Authenticate ("username", "password");
foreach (var message in messages) {
client.Send (message);
}
client.Disconnect (true);
}
}
也可以投射.NET 的 MailMessage 类到 MailKit :MimeMessage
public static void SendMessages (IList<MailMessage> messages)
{
...
foreach (var message in messages) {
var msg=(MimeMessage)message
client.Send(msg);
}
...
}
甚至:
var msgs=messages.Cast<MimeMessage>();
foreach(var msg in msgs)
{
...
}
评论
Windows 10, version 22H2