Owin自主主机SSL连接重置 [英] Owin self host SSL connection reset

查看:276
本文介绍了Owin自主主机SSL连接重置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在为自主主机Owin控制台应用程序设置HTTP时出现问题。浏览器始终显示连接重置错误。

I got an issue when setting up HTTPs for a self host Owin console application. The browser always shows a connection reset error.

我已尝试根据此链接手动创建证书 http://chavli.com/how-to-configure-owin-self-hosted-website-with-ssl/ 但我仍然在该端口上遇到连接重置问题。
我已经检查了Windows事件日志,并且没有错误消息。

I've tried creating certificates manually according to this link http://chavli.com/how-to-configure-owin-self-hosted-website-with-ssl/ but I still get the connection reset issue on that port. And I've checked the windows event log and there's no error messages.

应用程序将自行创建X509证书并自动运行netsh命令。

The application will create X509 certificate by itself and run netsh command automatically.

如果没有Ssl,应用程序可以正确显示网页。

Without Ssl, the application can display the web page correctly.

任何人都可以在下面运行我的代码并查看是否它可以在你的电脑上运行?
提前致谢。

Can any one run my code below and see whether it can work on your computer? Thanks in advance.

需要添加COM参考CertEnroll 1.0 Type Library来编译下面的代码(vs2015已在类型库中包含此COM引用)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using CERTENROLLLib;
using Microsoft.Owin.Hosting;
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;

namespace Owin.Startup
{
    class Program
    {
        static void Main(string[] args)
        {
            int port = 8888;
            string url = $"https://localhost:{port}";
            var cert = GetCert("localhost", TimeSpan.FromDays(3650), "devpwd", AppDomain.CurrentDomain.BaseDirectory + "cert.dat");
            ActivateCert(cert, port, GetAppId());
            using (WebApp.Start<Startup>(url))
            {
                Console.WriteLine($"Hosted: {url}");
                Console.ReadLine();
            }
        }

        static private string GetAppId()
        {
            Assembly assembly = Assembly.GetExecutingAssembly();

            //The following line (part of the original answer) is misleading.
            //**Do not** use it unless you want to return the System.Reflection.Assembly type's GUID.
            //Console.WriteLine(assembly.GetType().GUID.ToString());

            // The following is the correct code.
            var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0];
            var id = attribute.Value;
            return id;
        }
        static public X509Certificate2 GetCert(string cn, TimeSpan expirationLength, string pwd = "", string filename = null)
        {
            // http://stackoverflow.com/questions/18339706/how-to-create-self-signed-certificate-programmatically-for-wcf-service
            // http://stackoverflow.com/questions/21629395/http-listener-with-https-support-coded-in-c-sharp
            // https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.storename(v=vs.110).aspx
            // create DN for subject and issuer
            var base64encoded = string.Empty;
            if (filename != null && File.Exists(filename))
            {
                base64encoded = File.ReadAllText(filename);
            }
            else
            {
                base64encoded = CreateCertContent(cn, expirationLength, pwd);
                if (filename != null)
                {
                    File.WriteAllText(filename, base64encoded);
                }
            }
            // instantiate the target class with the PKCS#12 data (and the empty password)
            var rlt = new System.Security.Cryptography.X509Certificates.X509Certificate2(
                System.Convert.FromBase64String(base64encoded), pwd,
                // mark the private key as exportable (this is usually what you want to do)
                // mark private key to go into the Machine store instead of the current users store
                X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet
                );
            return rlt;
        }

        private static string CreateCertContent(string cn, TimeSpan expirationLength, string pwd)
        {
            string base64encoded = string.Empty;
            var dn = new CX500DistinguishedName();
            dn.Encode("CN=" + cn, X500NameFlags.XCN_CERT_NAME_STR_NONE);

            CX509PrivateKey privateKey = new CX509PrivateKey();
            privateKey.ProviderName = "Microsoft Strong Cryptographic Provider";
            privateKey.Length = 2048;
            privateKey.KeySpec = X509KeySpec.XCN_AT_KEYEXCHANGE;
            privateKey.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_DECRYPT_FLAG |
                                  X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_KEY_AGREEMENT_FLAG;
            privateKey.MachineContext = true;
            privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
            privateKey.Create();

            // Use the stronger SHA512 hashing algorithm
            var hashobj = new CObjectId();
            hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID,
                ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY,
                AlgorithmFlags.AlgorithmFlagsNone, "SHA512");

            // Create the self signing request
            var cert = new CX509CertificateRequestCertificate();
            cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, privateKey, "");
            cert.Subject = dn;
            cert.Issuer = dn; // the issuer and the subject are the same
            cert.NotBefore = DateTime.Now.Date;
            // this cert expires immediately. Change to whatever makes sense for you
            cert.NotAfter = cert.NotBefore + expirationLength;
            cert.HashAlgorithm = hashobj; // Specify the hashing algorithm
            cert.Encode(); // encode the certificate

            // Do the final enrollment process
            var enroll = new CX509Enrollment();
            enroll.InitializeFromRequest(cert); // load the certificate
            enroll.CertificateFriendlyName = cn; // Optional: add a friendly name
            string csr = enroll.CreateRequest(); // Output the request in base64
            // and install it back as the response
            enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate,
                csr, EncodingType.XCN_CRYPT_STRING_BASE64, pwd); // no password
            // output a base64 encoded PKCS#12 so we can import it back to the .Net security classes
            base64encoded = enroll.CreatePFX(pwd, // no password, this is for internal consumption
                PFXExportOptions.PFXExportChainWithRoot);
            return base64encoded;
        }

        private static void ActivateCert(X509Certificate2 rlt, int port, string appId)
        {
            X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadWrite);
            if (!store.Certificates.Contains(rlt))
            {
                store.Add(rlt);

                ProcessStartInfo psi = new ProcessStartInfo();
                psi.FileName = "netsh";

                psi.Arguments = $"http delete sslcert ipport=0.0.0.0:{port}";
                Process procDel = Process.Start(psi);
                procDel.WaitForExit();

                psi.Arguments = $"http add sslcert ipport=0.0.0.0:{port} certhash={rlt.Thumbprint} appid={{{appId}}}";
                Process proc = Process.Start(psi);
                proc.WaitForExit();

                psi.Arguments = $"http delete sslcert ipport=[::]:{port}";
                Process procDelV6 = Process.Start(psi);
                procDelV6.WaitForExit();

                psi.Arguments = $"http add sslcert ipport=[::]:{port} certhash={rlt.Thumbprint} appid={{{appId}}}";
                Process procV6 = Process.Start(psi);
                procV6.WaitForExit();

                psi.Arguments = $"http add urlacl url=https://+:{port}/ user={Environment.UserDomainName}\\{Environment.UserName}";
                Process procAcl = Process.Start(psi);
                procAcl.WaitForExit();
            }
            store.Close();
        }
    }

    public class Startup
    {
        private IAppBuilder app;
        public void Configuration(IAppBuilder app)
        {
#if DEBUG
            app.UseErrorPage();
#endif

            app.Use(new Func<AppFunc, AppFunc>(next => (async env =>
            {
                Console.WriteLine("Begin Request");
                foreach (var i in env.Keys)
                {
                    Console.WriteLine($"{i}\t={(env[i] == null ? "null" : env[i].ToString())}\t#\t{(env[i] == null ? "null" : env[i].GetType().FullName)}");
                }
                if (next != null)
                {
                    await next.Invoke(env);
                }
                else
                {
                    Console.WriteLine("Process Complete");
                }
                Console.WriteLine("End Request");
            })));

            app.UseWelcomePage("/");

            this.app = app;
        }


    }

}


推荐答案

您不应该使用从cert.dat加载的base64内容创建证书。尝试使用cert.Export(X509ContentType.Pfx,pwd)并使用新的X509Certificate2加载它(filename,pwd,X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

You should not create certificate with the base64 content which loaded from the cert.dat. Try using cert.Export(X509ContentType.Pfx, pwd) and load it with new X509Certificate2(filename, pwd, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

这篇关于Owin自主主机SSL连接重置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆