c# - Mono HTTPListener 在使用自签名 SSL 证书时抛出异常

标签 c# linux ssl mono

我使用 Mono HTTPListener 类在 Linux 上编写了一个小型 Web 服务器。它适用于 http 请求。但是,如果我使用自签名 SSL 证书(使用 openssl 创建并使用 httpcfg 安装),它会在浏览器请求进入时立即抛出无法捕获的异常。

异常(exception)情况是:

Unhandled Exception:
System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: The client stopped the handshake.
at Mono.Security.Protocol.Tls.SslServerStream.EndNegotiateHandshake (IAsyncResult asyncResult) <0xb4b079c8 + 0x001cf> in <filename unknown>:0 
at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult) <0xb4b07428 + 0x0005f> in <filename unknown>:0

完整代码如下:

using System;
using System.Net;
using System.IO;
using System.Text;
using System.Threading;

namespace SSLTest
{
    class MainClass
    {
        static void Main ()
        {
            try
            {
                HttpListener l = new HttpListener ();
                l.Prefixes.Add ("https://*:8443/");
                l.Start ();

                Console.WriteLine("Server is running.");
                while (l.IsListening)
                {
                    //create the worker thread
                    HttpListenerContext ctx = l.GetContext();   //.GetContext() blocks until something comes in
                    if(ctx != null)
                    {
                        if(ctx.Request.RemoteEndPoint != null)
                        {
                            Thread workerThread = new Thread(() => RunWorker(ctx));
                            workerThread.Start();
                        }
                    }
                }
                Console.WriteLine("Server is stopped.");
            }
            catch(Exception ex) 
            {
                Console.WriteLine ("Exception in Main: " + ex);
            }
        }


        static void RunWorker(HttpListenerContext ctx)
        {
            try
            {
                if(ctx.Request != null)
                {
                    if(ctx.Request.RemoteEndPoint != null)
                    {
                        Console.WriteLine ("Got request from " + ctx.Request.RemoteEndPoint.ToString());
                        string rstr = "Test Website!\n" + DateTime.Now.ToString();
                        byte[] buf = Encoding.UTF8.GetBytes(rstr);
                        if(buf!=null)
                        {
                            ctx.Response.ContentLength64 = buf.Length;
                            ctx.Response.OutputStream.Write(buf, 0, buf.Length);
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine ("@Exception in RunWorker: " + ex.Message);
            }
        }

    }
}

这是我第一次使用浏览器时的情况。浏览器会显示类似“证书不安全!是否继续(不推荐)?”之类的信息。如果我单击"is"并重新启动崩溃的服务器应用程序,它将从那时起正常工作。

我该如何解决这个问题?

此外,我无法使用 try block 捕获此异常。它总是会终止我的申请。我怎样才能防止这种情况发生?

最佳答案

应由未发布的错误修复程序修复 https://bugzilla.xamarin.com/show_bug.cgi?id=52675 ...虽然我还没有机会测试。

我也看到了这一点,目前正在努力寻找一种方法来处理异常。这看起来是 Mono 中的错误。

当证书验证以任何方式失败时都会发生。

我获得了一个 CA 签名证书,只要证书公用名 (dns) 与我尝试向其发送获取请求的 URL 中使用的 dns 相同,该证书就可以解决问题。如果我改为在 url 中指定公共(public) IP 地址(证书未注册),mono 应用程序将因未处理的异常而崩溃。

我们正在考虑的一个选项是实现一个基于 TCP 的网络服务器,它将使用 TcpListener 而不是沉重的 HttpListener,这反过来会解决我们看到的其他问题,当绑定(bind)到后面的内部 IP 时,单 httplistener 前缀无法正常工作一个 NAT。这意味着证书也可以通过编程方式绑定(bind),只是需要做更多的工作。

下面是一个非常粗略的版本。这绝不是一个成品,但它可能有助于帮助其他人在同一条道路上......我必须在两个答案中做到这一点,这是 tcp 网络服务器。

using System;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;

namespace Example.Lib.Net
{
    internal class TcpWebServer : IDisposable
    {
        private TcpListener m_Listener = null;
        private bool m_IsSSL = false;
        private X509Certificate2 m_ServerCertificate = null;

        internal X509Certificate2 ServerCertificate
        {
            get { return m_ServerCertificate; }
            set { m_ServerCertificate = value; }
        }

        internal void Start(string ip, int port, bool useSsl = false)
        {
            if (useSsl) // for player streams always use ssl to
            {
                m_IsSSL = true;
                m_ServerCertificate = new X509Certificate2("./cert/cert.pfx", "pass");

                X509Store store = new X509Store(StoreName.TrustedPublisher, StoreLocation.LocalMachine);
                store.Open(OpenFlags.ReadWrite);
                store.Add(m_ServerCertificate);
                store.Close();
            }

            IPAddress ipAddr = IPAddress.Any;
            if (ip != "*") IPAddress.TryParse(ip, out ipAddr);

            try
            {
                m_Listener = new TcpListener(ipAddr, port);
                m_Listener.Start();
                m_Listener.BeginAcceptTcpClient(OnClientAccepted, m_Listener);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        private void OnClientAccepted(IAsyncResult ar)
        {
            TcpListener listener = ar.AsyncState as TcpListener;

            if (listener == null)
                return;

            TcpClient client = listener.EndAcceptTcpClient(ar);
            client.ReceiveBufferSize = 65535;
            client.Client.ReceiveBufferSize = 65535;

            TcpWebConnection con = new TcpWebConnection(client, this, m_IsSSL);

            listener.BeginAcceptTcpClient(OnClientAccepted, listener);
        }
    }
}

关于c# - Mono HTTPListener 在使用自签名 SSL 证书时抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38835314/

相关文章:

c# - 通过此代码更改音频采样率,当前会更改位深度吗?

asp.net - 当网站位于服务于 TLS 证书的负载均衡器后面时,将 cookie 标记为表单例份验证中的 "secure"

windows - 用于在 Windows 上更正 Linux 文件名的脚本,反之亦然?

android - 这个内核源码能用吗?

apache - https htaccess 排除一些 url

ssl - nginx 强制 ssl http

c# - 将当前页面 url 作为 url 中的参数传递

c# - 发送 HTTP header 后服务器无法设置内容类型

c# - 使用 LINQ 登录到 Twitter

linux - 在 Linux 上使用手动 STAF 命令