2015-11-20 8 views
4

У меня возникла проблема при настройке HTTP-сообщений для консольного приложения OWA для хоста. Браузер всегда показывает ошибку сброса соединения.Owin self host Сброс SSL-соединения

Я пробовал создавать сертификаты вручную в соответствии с этой ссылкой http://chavli.com/how-to-configure-owin-self-hosted-website-with-ssl/, но я все еще получаю ошибку сброса соединения на этом порту. И я проверил журнал событий Windows, и нет сообщений об ошибках.

Приложение создаст сертификат X509 самостоятельно и автоматически выполнит команду netsh.

Без Ssl приложение может отображать веб-страницу правильно.

Можно ли запустить мой код ниже и посмотреть, может ли он работать на вашем компьютере? Спасибо заранее.

нужно добавить 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; 
     } 


    } 

} 
+0

Возможно, что что-то не так с вашим сертифицированным вручную сертификатом, чтобы он не смог установить начальное соединение. В журналах событий может быть что-то. Попробуйте использовать эти инструменты генерации сертификатов и посмотрите, сможете ли вы заставить их работать. – Tratcher

+0

Я попытался создать сертификат вручную с помощью IIS, но все еще получил проблему с перезагрузкой соединения. Я пробовал на двух разных компьютерах с теми же шагами, о которых говорилось выше, и оба дают мне ошибку сброса соединения ssl на этом порту. Я не знаю, что делать сейчас. – mind1n

ответ

2

Вы не должны создать сертификат с содержанием base64, которые загружаются из cert.dat. Попробуйте использовать cert.Export (X509ContentType.Pfx, pwd) и загрузите его новым X509Certificate2 (имя файла, pwd, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);