Windows Server 2022 的自签名证书给出ERR_SSL_KEY_USAGE_INCOMPATIBLE错误

Self Signed Certificate Giving ERR_SSL_KEY_USAGE_INCOMPATIBLE Error with Windows Server 2022

提问人:Sahin 提问时间:8/15/2023 最后编辑:Sahin 更新时间:8/15/2023 访问量:929

问:

我正在创建这样的自签名证书(您也可以在此答案中找到它:https://stackoverflow.com/a/13806300/5243037):

        public static X509Certificate2 CreateSelfSignedCertificate(string friendlyName, string password)
        {
            // create DN for subject and issuer
            var dnHostName = new CX500DistinguishedName();
            // DN will be in format CN=machinename, DC=domain, DC=local for machinename.domain.local
            dnHostName.Encode(GetMachineDn());
            var dnSubjectName = dnHostName;

            var dn = new CX500DistinguishedName();
            dn.Encode("CN=" + friendlyName, X500NameFlags.XCN_CERT_NAME_STR_NONE);

            //var privateKey = new CX509PrivateKey();
            var typeName = "X509Enrollment.CX509PrivateKey";
            var type = Type.GetTypeFromProgID(typeName);
            if (type == null)
            {
                throw new Exception(typeName + " is not available on your system: 0x80040154 (REGDB_E_CLASSNOTREG)");
            }

            var privateKey = Activator.CreateInstance(type) as IX509PrivateKey;
            if (privateKey == null)
            {
                throw new Exception("Your certlib does not know an implementation of " + typeName +
                                    " (in HKLM:\\SOFTWARE\\Classes\\Interface\\)!");
            }
            privateKey.ProviderName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
            privateKey.ProviderType = X509ProviderType.XCN_PROV_RSA_AES;
            // key-bitness
            privateKey.Length = 2048;
            privateKey.KeySpec = X509KeySpec.XCN_AT_KEYEXCHANGE;
            privateKey.MachineContext = true;
            // Don't allow export of private key
            privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_NONE;

            // use is not limited
            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");

            // add extended key usage if you want - look at MSDN for a list of possible OIDs
            var oid = new CObjectId();
            oid.InitializeFromValue("1.3.6.1.5.5.7.3.1"); // SSL server
            var oidlist = new CObjectIds { oid };
            var eku = new CX509ExtensionEnhancedKeyUsage();
            eku.InitializeEncode(oidlist);

            // add all IPs of current machine as dns-names (SAN), so a user connecting to our wcf 
            // service by IP still claim-trusts this server certificate
            var objExtensionAlternativeNames = new CX509ExtensionAlternativeNames();
            {
                var altNames = new CAlternativeNames();
                var dnsHostname = new CAlternativeName();
                dnsHostname.InitializeFromString(AlternativeNameType.XCN_CERT_ALT_NAME_DNS_NAME, Environment.MachineName);
                altNames.Add(dnsHostname);
                foreach (var ipAddress in Dns.GetHostAddresses(Dns.GetHostName()))
                {
                    if ((ipAddress.AddressFamily == AddressFamily.InterNetwork ||
                         ipAddress.AddressFamily == AddressFamily.InterNetworkV6) && !IPAddress.IsLoopback(ipAddress))
                    {
                        var dns = new CAlternativeName();
                        dns.InitializeFromString(AlternativeNameType.XCN_CERT_ALT_NAME_DNS_NAME, ipAddress.ToString());
                        altNames.Add(dns);
                    }
                }
                objExtensionAlternativeNames.InitializeEncode(altNames);
            }

            // Create the self signing request
            //var cert = new CX509CertificateRequestCertificate();
            typeName = "X509Enrollment.CX509CertificateRequestCertificate";
            type = Type.GetTypeFromProgID(typeName);
            if (type == null)
            {
                throw new Exception(typeName + " is not available on your system: 0x80040154 (REGDB_E_CLASSNOTREG)");
            }
            var cert = Activator.CreateInstance(type) as IX509CertificateRequestCertificate;
            if (cert == null)
            {
                throw new Exception("Your certlib does not know an implementation of " + typeName +
                                    " (in HKLM:\\SOFTWARE\\Classes\\Interface\\)!");
            }
            cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, privateKey, "");
            cert.Subject = dn;
            cert.Issuer = dn; // the issuer and the subject are the same
            cert.NotBefore = DateTime.Now.AddDays(-1);
            // this cert expires immediately. Change to whatever makes sense for you
            cert.NotAfter = DateTime.Today.AddYears(200);
            cert.X509Extensions.Add((CX509Extension)eku); // add the EKU
            cert.X509Extensions.Add((CX509Extension)objExtensionAlternativeNames);
            cert.HashAlgorithm = hashobj; // Specify the hashing algorithm
            cert.Encode(); // encode the certificate

            // Do the final enrollment process
            //var enroll = new CX509Enrollment();
            typeName = "X509Enrollment.CX509Enrollment";
            type = Type.GetTypeFromProgID(typeName);
            if (type == null)
            {
                throw new Exception(typeName + " is not available on your system: 0x80040154 (REGDB_E_CLASSNOTREG)");
            }
            var enroll = Activator.CreateInstance(type) as IX509Enrollment;
            if (enroll == null)
            {
                throw new Exception("Your certlib does not know an implementation of " + typeName +
                                    " (in HKLM:\\SOFTWARE\\Classes\\Interface\\)!");
            }
            // Use private key to initialize the certrequest...
            enroll.InitializeFromRequest(cert);
            enroll.CertificateFriendlyName = friendlyName; // Optional: add a friendly name
            var 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, password);

            // This will fail on Win2k8, some strange "Parameter is empty" error... Thus we search the
            // certificate by serial number with the managed X509Store-class
            // // output a base64 encoded PKCS#12 so we can import it back to the .Net security classes
            //var base64Encoded = enroll.CreatePFX(password, PFXExportOptions.PFXExportChainNoRoot, EncodingType.XCN_CRYPT_STRING_BASE64);
            //return new X509Certificate2(Convert.FromBase64String(base64Encoded), password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
            //CertificateExists(friendlyName);
            var certFs = LoadCertFromStore(friendlyName);
            if (!certFs.HasPrivateKey)
                throw new InvalidOperationException("Created certificate has no private key!");

            return certFs;
        }

这已经工作了一段时间,但是当我们在 Windows Server 2022 上设置此服务器时,以及当我们使用基于 Chromium 的浏览器(Edge、Opera、Chrome)时,我们收到ERR_SSL_KEY_USAGE_INCOMPATIBLE错误。顺便说一句,我们在Firefox上没有收到任何错误。 当我使用 Powershell 命令手动创建自签名证书时:
New-SelfSignedCertificate -Subject "CN=WebServer 444" -CertStoreLocation "cert:\LocalMachine\My"

并使用 cmd 命令:
证书工作正常。
netsh http add sslcert ipport=0.0.0.0:444 appid={"blabla-bla-bla-bla-blabla"} certhash=<THUMBPRINT>

详: .Net 框架 4.6.2 Visual Studio 2022

可能有什么问题?

C# Google-Chrome SSL 自签名证书 Windows-Server-2022

评论


答: 暂无答案