Owin SSL firefox收到的数据真实性无法验证错误

时间:2015-12-03 14:31:47

标签: firefox ssl certificate owin self-hosting

我想知道是否有人可以运行下面的代码,看看为什么firefox无法正确地与owin SSL服务器通信?它在Chrome& IE。

我尝试手动将pfx导入到firefox中,但仍然无法正确地与owin服务器通信。

参考下面的代码,我创建了一个支持SSL的owin http服务器,它可以生成&安装证书&将证书自动绑定到端口。

但是,当我在不同的浏览器中测试时,我发现了一个问题。 firefox浏览器始终显示一条错误消息,指示:

  

在页面加载时重置了与服务器的连接。

     

您要查看的页面无法显示,因为   无法验证收到数据的真实性。请   联系网站所有者告知他们这个问题。

Chrome& IE可以正确显示页面。

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>;
using System.Security.Permissions;
using System.Security.Policy;

namespace Owin.Startup
{
    class Program
    {
        static void Main(string[] args)
        {
            int port = 7878;

            var cert = GetCert("localhost", TimeSpan.FromDays(3650), "devpwd", AppDomain.CurrentDomain.BaseDirectory + "cert.pfx");
            ActivateCert((X509Certificate2)cert, port, GetAppId());
            StartOptions so = new StartOptions();
            so.Urls.Add($"https://+:{port}/");
            using (WebApp.Start<Startup>(so))
            {
                Console.WriteLine($"Hosted on port: {port}");
                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 X509Certificate 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
            System.Security.Cryptography.X509Certificates.X509Certificate cert = null;
            if (filename != null && File.Exists(filename))
            {
                cert = new X509Certificate2(filename, pwd, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
            }
            else
            {
                var base64encoded = string.Empty;
                base64encoded = CreateCertContent(cn, expirationLength, pwd);
                cert = 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
                    );
                File.WriteAllBytes(filename, cert.Export(X509ContentType.Pfx, pwd));
            }
            // instantiate the target class with the PKCS#12 data (and the empty password)

            return cert;
        }

        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;
        }


    }

}

1 个答案:

答案 0 :(得分:2)

在firefox中,输入about:config并搜索dhe。 该列表显示了firefox支持的所有密码算法。 但是,我注意到你使用的是最新的firefox不支持的SHA512。 请将算法修改为sha256,它应该在firefox中工作:)