2015-11-20 68 views
4

爲自主主機Owin控制檯應用程序設置HTTP時出現問題。瀏覽器始終顯示連接重置錯誤。Owin自主主機SSL連接重置

我試着根據這個鏈接http://chavli.com/how-to-configure-owin-self-hosted-website-with-ssl/手動創建證書,但我仍然在該端口上得到連接重置問題。 我檢查了Windows事件日誌,並沒有錯誤消息。

該應用程序將自行創建X509證書並自動運行netsh命令。

沒有Ssl,應用程序可以正確顯示網頁。

任何人都可以在下面運行我的代碼並查看它是否可以在您的計算機上工作? 在此先感謝。

需要添加COM參考CertEnroll 1.0類型庫編譯下面的代碼(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; 
     } 


    } 

} 
+0

也許手工製作的證書有問題,所以在建立初始連接後會失敗。事件日誌中可能有某些內容。嘗試使用這些證書生成工具,看看你是否可以使它工作。 – Tratcher

+0

我嘗試使用IIS手動創建證書,但仍然出現連接重置問題。我在2臺不同的計算機上嘗試了上面提到的相同步驟,並且都在該端口上給我一個ssl連接重置錯誤。我不知道現在該做什麼。 – mind1n

回答

2

你不應該創建與從加載的base64內容證書cert.dat。嘗試使用cert.Export(X509ContentType.Pfx,pwd)並使用新的X509Certificate2(文件名,pwd,X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet)加載它。