我想编写(使用C#和dotnet 4.8)使用TLS进行安全保护的TCP服务。为此,我想将SslStream与TcpListener一起使用,但是我不断收到奇怪的错误。
我的实验程序如下。简单来说:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
namespace TestTlsService
{
class Program
{
static string tempCert;
static void Main(string[] args)
{
/* Create a cert. */
var cr = new CertificateRequest("cn=this.is.invalid", ECDsa.Create(), HashAlgorithmName.SHA256);
using (var cert = cr.CreateSelfSigned(DateTime.UtcNow.AddDays(-1), DateTime.UtcNow.AddYears(+1)))
{
var exp = cert.Export(X509ContentType.Pfx);
tempCert = Path.Combine(Path.GetTempPath(), "MySelfSignedCert.pfx");
File.WriteAllBytes(tempCert, exp);
}
/* Launch a service thread. */
Thread svc = new Thread(ServiceMain);
svc.Start();
Thread.Sleep(100);
/* Connect as a client. */
using (var tcp = new TcpClient())
{
tcp.Connect("localhost", 1984);
var stream = tcp.GetStream();
/* Read the line "GoTLS" from the server. */
var insecureLine = ReadLine(stream);
/* Hand over control to TLS. */
using (var tls = new SslStream(stream, false, CheckCert))
{
tls.AuthenticateAsClient("this.is.invalid");
/* Read a different line, this time securely. */
string line = ReadLine(tls);
}
}
}
static void ServiceMain()
{
/* Open a listener and start listening. */
var listen = new TcpListener(IPAddress.Loopback, 1984);
listen.Start();
using (var tcp = listen.AcceptTcpClient())
{
/* Send "GoTLS" to the client insecurely. */
var stream = tcp.GetStream();
stream.Write(Encoding.ASCII.GetBytes("GoTLS\r\n"), 0, 7);
/* Hand over control to TLS, using the self-signed cert from earlier. */
using (var tls = new SslStream(stream))
{
var cert = new X509Certificate2(tempCert);
tls.AuthenticateAsServer(cert);
/* Send a new message inside the secure channel. */
tls.Write(Encoding.ASCII.GetBytes("Hello\r\n"), 0, 7);
}
}
}
/* Simple function that just reads a line. */
static string ReadLine(Stream stream)
{
byte[] line = new byte[100];
int bytesIn = stream.Read(line, 0, 100);
string lineAscii = Encoding.ASCII.GetString(line, 0, bytesIn);
return lineAscii;
}
/* Accept all certificates. DO NOT COPY THIS INTO YOUR OWN CODE! */
private static bool CheckCert(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
/* The full version will check the cert, but for now we'll just... */
return true;
}
}
}
该程序在AuthenticateAsServer行中引发AuthenticationException,并显示消息“对SSPI的调用失败,请参阅内部异常”。而内部异常具有“客户端和服务器无法通信,因为它们不具有通用算法”。我发现SslStream库本身找不到通用协议的可能性很小。
我怀疑问题的根源在于我使用的是自签名证书,因为我可以找到的所有AuthenticateAsServer示例都使用预生成的证书文件,可惜我没有。
如何在服务器端使用SslStream与自签名证书协商TLS?
要抢先预期的问题...
我知道客户端可以正常工作,因为我已用邮件服务器替换了“ localhost”(并跳过了“只读”行),并且客户端线程可以正常工作,以读取TLS发出后远程邮件服务器发送的安全欢迎行经过谈判。
设置ServicePointManager.SecurityProtocol
为Tls12
无济于事。
如果删除pre-SslStream“ GoTLS”交换,则会收到相同的错误。
我搜索了错误消息。我能找到的所有答案都建议将SecurityProtocol设置为Tls12,我已经尝试过了。
我尝试使用其他格式的证书而不是PFX,但是在抱怨缺少私钥时遇到了其他错误。
我不知道为什么,但是不喜欢您签发的ECDSA证书。如果改为使用标准RSA:
var cr = new CertificateRequest(new X500DistinguishedName("cn=this.is.invalid"), RSA.Create(), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
并保留其他所有内容-然后它将按预期工作。从理论上讲,TLS支持ECC(椭圆曲线)密钥,但是我对此并不熟练,并且不确定为什么SslStream.AuthenticateAsServer
不喜欢该证书。希望您不需要专门的ECC,那么使用RSA的上述解决方法就可以了。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句