C#:强制 TLS1.2 但 Https 服务器仍然给出常见算法错误

Posted

技术标签:

【中文标题】C#:强制 TLS1.2 但 Https 服务器仍然给出常见算法错误【英文标题】:C#: Forcing TLS1.2 but Https server still giving common algorithm error 【发布时间】:2019-01-21 13:39:35 【问题描述】:

我正在尝试使用 TcpClient、SslStream 和自签名证书设置一个简单的 HTTPS Web 服务器。

代码开始正常,显示等待客户端,但是当我通过网络浏览器连接到它时,我得到了

"调用 SSPI 失败,客户端和服务器无法通信, 因为他们没有共同的算法”

根据我的阅读,这通常意味着服务器正在尝试使用客户端没有或无法使用的协议类型(IE:过时),并且许多人说要确保服务器和客户端都在使用TLS 1.2。

-我已确保包含"ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12" 以强制执行 tls1.2,并且正在使用我已验证为最新且可与 tls12 配合使用的 Firefox(和其他)。

-我在 .net 4.7 上,所以我认为这不应该是一个问题。

-我已手动将证书导入到 firefox。

-我试过允许所有协议,没有协议,和“默认”

-我已进入注册表并启用了所有 TLS,并禁用了除 tls1.2 之外的所有 TLS,两者结果相同。

我确定这个问题之前已经回答过了,但是我已经搜索 SO 和 google 了几天了,所以我放弃了,烤掉!

静态 X509Certificate serverCertificate = null;

public static int Main(string[] args)

    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;  //Force tls 1.2
    MakeCert();                                                         //Create self signed certificate and assign to serverCertificate
    SslTcpServer.RunServer();
    return 0;


static void MakeCert()

    var ecdsa = ECDsa.Create(); // generate asymmetric key pair
    var req = new CertificateRequest("cn=localhost", ecdsa, HashAlgorithmName.SHA256);
    var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5));

    // Create PFX (PKCS #12) with private key
    string pfxPath = Path.Combine(Environment.CurrentDirectory, "mycert.pfx");
    File.WriteAllBytes(pfxPath, cert.Export(X509ContentType.Pfx, "Password"));
    // Create Base 64 encoded CER (public key only)
    string cerPath = Path.Combine(Environment.CurrentDirectory, "mycert.cer");
    File.WriteAllText(cerPath,
        "-----BEGIN CERTIFICATE-----\r\n"
        + Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks)
        + "\r\n-----END CERTIFICATE-----");

    string keyfilename = "mycert.pfx";
    string certpath = Path.Combine(Environment.CurrentDirectory, keyfilename);
    X509Certificate certificate = new X509Certificate2(certpath, "Password");
    serverCertificate = certificate;


public static void RunServer()

    TcpListener listener = new TcpListener(IPAddress.Any, 8080);
    listener.Start();
    while (true)
    
        Console.WriteLine("Waiting for a client to connect...");
        TcpClient client = listener.AcceptTcpClient();
        ProcessClient(client);
    


static void ProcessClient(TcpClient client)

    SslStream sslStream = new SslStream(client.GetStream(), false);
    try
    
        sslStream.AuthenticateAsServer(serverCertificate, clientCertificateRequired: false, enabledSslProtocols : SslProtocols.Tls12, checkCertificateRevocation: false);
        Console.WriteLine("Authenticated");
    
    catch (AuthenticationException e)
    
        Console.WriteLine("Exception: 0", e.Message);
        if (e.InnerException != null)
        
            Console.WriteLine("Inner exception: 0", e.InnerException.Message);
        
        Console.WriteLine("Authentication failed - closing the connection.");
        sslStream.Close();
        client.Close();
        return;
    
    finally
    
        sslStream.Close();
        client.Close();
    

代码永远不会达到“Authenticated”,总是抛出异常

“对 SSPI 的调用失败,请参阅内部异常”

内部异常

"客户端和服务器无法通信,因为它们不具备 通用算法”

【问题讨论】:

AFAIR .Net 使用 Windows 的 schannel 库进行 TLS 通信。因此,Windows 版本决定了哪些密码套件和 tls 模式可用。 【参考方案1】:

此问题与 SSL/TLS 协议无关。这是关于签名算法ECDsa的。看起来 Firefox 不支持 nistP521ECDsa.Create 使用的默认曲线)(我没有检查任何文档),因为它与 nistP256 或 nistP384 完美配合

  var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP384); // generate asymmetric key pair
  var req = new CertificateRequest("cn=localhost",ecdsa, HashAlgorithmName.SHA256);

【讨论】:

以上是关于C#:强制 TLS1.2 但 Https 服务器仍然给出常见算法错误的主要内容,如果未能解决你的问题,请参考以下文章

BizTalk 2016 管理员因强制 tls1.1+ 而失败

如何强制 java 服务器只接受 tls 1.2 并拒绝 tls 1.0 和 tls 1.1 连接

iOS 9改用HTTPS,适配HTTP

2017 苹果强制https

更新 .NET Web 服务以使用 TLS 1.2

C# 和 dotnet 4.7.1 没有为 TLS 1.2 调用添加自定义证书