internal static SslPolicyErrors BuildChainAndVerifyProperties(X509Chain chain, X509Certificate2 remoteCertificate, bool checkCertName, bool isServer, string?hostName) { SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None; bool chainBuildResult = chain.Build(remoteCertificate); if (!chainBuildResult && // Build failed on handle or on policy. chain.SafeHandle !.DangerousGetHandle() == IntPtr.Zero) // Build failed to generate a valid handle. { throw new CryptographicException(Marshal.GetLastPInvokeError()); } if (checkCertName) { unsafe { uint status = 0; var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA() { cbSize = (uint)sizeof(Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA), // Authenticate the remote party: (e.g. when operating in server mode, authenticate the client). dwAuthType = isServer ? Interop.Crypt32.AuthType.AUTHTYPE_CLIENT : Interop.Crypt32.AuthType.AUTHTYPE_SERVER, fdwChecks = 0, pwszServerName = null }; var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA() { cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_PARA), dwFlags = 0, pvExtraPolicyPara = &eppStruct }; fixed(char *namePtr = hostName) { eppStruct.pwszServerName = (ushort *)namePtr; cppStruct.dwFlags |= (Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG); SafeX509ChainHandle chainContext = chain.SafeHandle !; status = Verify(chainContext, ref cppStruct); if (status == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } } } if (!chainBuildResult) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; } return(sslPolicyErrors); }
public static void BuildChain( X509Certificate2 certificate, X509Certificate2Collection remoteCertificateStore, string hostName, bool checkCertificateRevocationList, out X509Chain chain, out SslPolicyErrors sslPolicyErrors) { chain = null; sslPolicyErrors = SslPolicyErrors.None; // Build the chain. chain = new X509Chain(); chain.ChainPolicy.RevocationMode = checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; // Authenticate the remote party: (e.g. when operating in client mode, authenticate the server). chain.ChainPolicy.ApplicationPolicy.Add(s_serverAuthOid); if (remoteCertificateStore.Count > 0) { if (NetEventSource.Log.IsEnabled()) { foreach (X509Certificate cert in remoteCertificateStore) { NetEventSource.Info(remoteCertificateStore, $"Adding cert to ExtraStore: {cert.Subject}"); } } chain.ChainPolicy.ExtraStore.AddRange(remoteCertificateStore); } if (!chain.Build(certificate)) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; } // Verify the hostName matches the certificate. unsafe { Interop.Crypt32.CERT_CHAIN_POLICY_PARA cppStruct = default; cppStruct.cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_PARA); cppStruct.dwFlags = 0; Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = default; eppStruct.cbSize = (uint)sizeof(Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA); eppStruct.dwAuthType = Interop.Crypt32.AuthType.AUTHTYPE_SERVER; cppStruct.pvExtraPolicyPara = &eppStruct; fixed(char *namePtr = hostName) { eppStruct.pwszServerName = namePtr; cppStruct.dwFlags = Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG; Interop.Crypt32.CERT_CHAIN_POLICY_STATUS status = default; status.cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_STATUS); if (Interop.Crypt32.CertVerifyCertificateChainPolicy( (IntPtr)Interop.Crypt32.CertChainPolicy.CERT_CHAIN_POLICY_SSL, chain.SafeHandle, ref cppStruct, ref status)) { if (status.dwError == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(certificate, nameof(Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH)); } sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } else { // Failure checking the policy. This is a rare error. We will assume the name check failed. if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(certificate, $"Failure calling {nameof(Interop.Crypt32.CertVerifyCertificateChainPolicy)}"); } sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } } }
internal static SslPolicyErrors VerifyCertificateProperties( X509Chain chain, X509Certificate2 remoteCertificate, bool checkCertName, bool isServer, string hostName) { SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None; if (!chain.Build(remoteCertificate) // Build failed on handle or on policy. && chain.SafeHandle.DangerousGetHandle() == IntPtr.Zero) // Build failed to generate a valid handle. { throw new CryptographicException(Marshal.GetLastWin32Error()); } if (checkCertName) { unsafe { uint status = 0; var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA() { cbSize = (uint)Marshal.SizeOf<Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA>(), dwAuthType = isServer ? Interop.Crypt32.AuthType.AUTHTYPE_SERVER : Interop.Crypt32.AuthType.AUTHTYPE_CLIENT, fdwChecks = 0, pwszServerName = null }; var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA() { cbSize = (uint)Marshal.SizeOf<Interop.Crypt32.CERT_CHAIN_POLICY_PARA>(), dwFlags = 0, pvExtraPolicyPara = &eppStruct }; fixed (char* namePtr = hostName) { eppStruct.pwszServerName = namePtr; cppStruct.dwFlags |= (Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG); SafeX509ChainHandle chainContext = chain.SafeHandle; status = Verify(chainContext, ref cppStruct); if (status == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } } } X509ChainStatus[] chainStatusArray = chain.ChainStatus; if (chainStatusArray != null && chainStatusArray.Length != 0) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; } return sslPolicyErrors; }
internal static SslPolicyErrors VerifyCertificateProperties( X509Chain chain, X509Certificate2 remoteCertificate, bool checkCertName, bool isServer, string hostName) { SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None; if (!chain.Build(remoteCertificate) && // Build failed on handle or on policy. chain.SafeHandle.DangerousGetHandle() == IntPtr.Zero) // Build failed to generate a valid handle. { throw new CryptographicException(Marshal.GetLastWin32Error()); } if (checkCertName) { unsafe { uint status = 0; var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA() { cbSize = (uint)Marshal.SizeOf <Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA>(), dwAuthType = isServer ? Interop.Crypt32.AuthType.AUTHTYPE_SERVER : Interop.Crypt32.AuthType.AUTHTYPE_CLIENT, fdwChecks = 0, pwszServerName = null }; var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA() { cbSize = (uint)Marshal.SizeOf <Interop.Crypt32.CERT_CHAIN_POLICY_PARA>(), dwFlags = 0, pvExtraPolicyPara = &eppStruct }; fixed(char *namePtr = hostName) { eppStruct.pwszServerName = namePtr; cppStruct.dwFlags |= (Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG); SafeX509ChainHandle chainContext = chain.SafeHandle; status = Verify(chainContext, ref cppStruct); if (status == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } } } X509ChainStatus[] chainStatusArray = chain.ChainStatus; if (chainStatusArray != null && chainStatusArray.Length != 0) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; } return(sslPolicyErrors); }
internal static SslPolicyErrors VerifyCertificateProperties( SafeDeleteContext securityContext, X509Chain chain, X509Certificate2 remoteCertificate, bool checkCertName, bool isServer, string hostName) { SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None; bool chainBuildResult = chain.Build(remoteCertificate); if (!chainBuildResult && // Build failed on handle or on policy. chain.SafeHandle.DangerousGetHandle() == IntPtr.Zero) // Build failed to generate a valid handle. { throw new CryptographicException(Interop.CPError.GetLastWin32Error()); } if (checkCertName) { unsafe { uint status = 0; var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA() { cbSize = (uint)sizeof(Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA), // Authenticate the remote party: (e.g. when operating in server mode, authenticate the client). dwAuthType = isServer ? Interop.Crypt32.AuthType.AUTHTYPE_CLIENT : Interop.Crypt32.AuthType.AUTHTYPE_SERVER, fdwChecks = 0, pwszServerName = null }; var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA() { cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_PARA), dwFlags = 0, pvExtraPolicyPara = &eppStruct }; //convert 2 byte wchar to 4 byte wchar var buf = new byte[(hostName.Length + 1) * 4]; var byte_str = Encoding.Unicode.GetBytes(hostName); for (int i = 0; i < hostName.Length; i++) { buf[i * 4] = byte_str[i * 2]; buf[i * 4 + 1] = byte_str[i * 2 + 1]; } fixed(byte *namePtr = buf) { eppStruct.pwszServerName = (char *)namePtr; cppStruct.dwFlags |= (Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG); SafeX509ChainHandle chainContext = chain.SafeHandle; status = Verify(chainContext, ref cppStruct); if (status == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } } } if (!chainBuildResult) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; } return(sslPolicyErrors); }
// TODO: Issue #2165. Merge with similar code used in System.Net.Security move to Common/src//System/Net. public static void BuildChain( X509Certificate2 certificate, string hostName, bool checkCertificateRevocationList, out X509Chain chain, out SslPolicyErrors sslPolicyErrors) { chain = null; sslPolicyErrors = SslPolicyErrors.None; // Build the chain. chain = new X509Chain(); chain.ChainPolicy.RevocationMode = checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; if (!chain.Build(certificate)) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; } // Verify the hostName matches the certificate. unsafe { var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA(); cppStruct.cbSize = (uint)Marshal.SizeOf<Interop.Crypt32.CERT_CHAIN_POLICY_PARA>(); cppStruct.dwFlags = 0; var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA(); eppStruct.cbSize = (uint)Marshal.SizeOf<Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA>(); eppStruct.dwAuthType = Interop.Crypt32.AuthType.AUTHTYPE_CLIENT; cppStruct.pvExtraPolicyPara = &eppStruct; fixed (char* namePtr = hostName) { eppStruct.pwszServerName = namePtr; cppStruct.dwFlags = Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG; var status = new Interop.Crypt32.CERT_CHAIN_POLICY_STATUS(); status.cbSize = (uint)Marshal.SizeOf<Interop.Crypt32.CERT_CHAIN_POLICY_STATUS>(); if (Interop.Crypt32.CertVerifyCertificateChainPolicy( (IntPtr)Interop.Crypt32.CertChainPolicy.CERT_CHAIN_POLICY_SSL, chain.SafeHandle, ref cppStruct, ref status)) { if (status.dwError == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } else { // Failure checking the policy. This is a rare error. We will assume the name check failed. // TODO: Issue #2165. Log this error or perhaps throw an exception instead. sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } } }
/*++ VerifyRemoteCertificate - Validates the content of a Remote Certificate checkCRL if true, checks the certificate revocation list for validity. checkCertName, if true checks the CN field of the certificate --*/ //This method validates a remote certificate. //SECURITY: The scenario is allowed in semitrust StorePermission is asserted for Chain.Build // A user callback has unique signature so it is safe to call it under permission assert. // internal bool VerifyRemoteCertificate(RemoteCertValidationCallback remoteCertValidationCallback) { GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate"); SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None; // We don't catch exceptions in this method, so it's safe for "accepted" be initialized with true. bool success = false; X509Chain chain = null; X509Certificate2 remoteCertificateEx = null; try { X509Certificate2Collection remoteCertificateStore; remoteCertificateEx = GetRemoteCertificate(out remoteCertificateStore); _isRemoteCertificateAvailable = remoteCertificateEx != null; if (remoteCertificateEx == null) { GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate (no remote cert)", (!_remoteCertRequired).ToString()); sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable; } else { chain = new X509Chain(); chain.ChainPolicy.RevocationMode = _checkCertRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; if (remoteCertificateStore != null) { chain.ChainPolicy.ExtraStore.AddRange(remoteCertificateStore); } if (!chain.Build(remoteCertificateEx) // Build failed on handle or on policy. && chain.SafeHandle.DangerousGetHandle() == IntPtr.Zero) // Build failed to generate a valid handle. { throw new CryptographicException(Marshal.GetLastWin32Error()); } if (_checkCertName) { unsafe { uint status = 0; var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA() { cbSize = (uint)Marshal.SizeOf<Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA>(), dwAuthType = IsServer ? Interop.Crypt32.AuthType.AUTHTYPE_SERVER : Interop.Crypt32.AuthType.AUTHTYPE_CLIENT, fdwChecks = 0, pwszServerName = null }; var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA() { cbSize = (uint)Marshal.SizeOf<Interop.Crypt32.CERT_CHAIN_POLICY_PARA>(), dwFlags = 0, pvExtraPolicyPara = &eppStruct }; fixed (char* namePtr = _hostName) { eppStruct.pwszServerName = namePtr; cppStruct.dwFlags |= (Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG); SafeX509ChainHandle chainContext = chain.SafeHandle; status = Verify(chainContext, ref cppStruct); if (status == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } } } X509ChainStatus[] chainStatusArray = chain.ChainStatus; if (chainStatusArray != null && chainStatusArray.Length != 0) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; } } if (remoteCertValidationCallback != null) { success = remoteCertValidationCallback(_hostName, remoteCertificateEx, chain, sslPolicyErrors); } else { if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNotAvailable && !_remoteCertRequired) { success = true; } else { success = (sslPolicyErrors == SslPolicyErrors.None); } } if (Logging.On) { if (sslPolicyErrors != SslPolicyErrors.None) { Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_has_errors); if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0) { Logging.PrintInfo(Logging.Web, this, "\t" + SR.net_log_remote_cert_not_available); } if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0) { Logging.PrintInfo(Logging.Web, this, "\t" + SR.net_log_remote_cert_name_mismatch); } if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0) { foreach (X509ChainStatus chainStatus in chain.ChainStatus) { Logging.PrintInfo(Logging.Web, this, "\t" + chainStatus.StatusInformation); } } } if (success) { if (remoteCertValidationCallback != null) { Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_user_declared_valid); } else { Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_has_no_errors); } } else { if (remoteCertValidationCallback != null) { Logging.PrintInfo(Logging.Web, this, SR.net_log_remote_cert_user_declared_invalid); } } } GlobalLog.Print("Cert Validation, remote cert = " + (remoteCertificateEx == null ? "<null>" : remoteCertificateEx.ToString(true))); } finally { // At least on Win2k server the chain is found to have dependencies on the original cert context. // So it should be closed first. if (chain != null) { chain.Dispose(); } if (remoteCertificateEx != null) { remoteCertificateEx.Dispose(); } } GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::VerifyRemoteCertificate", success.ToString()); return success; }
// TODO: Issue #2165. Merge with similar code used in System.Net.Security move to Common/src//System/Net. public static void BuildChain( X509Certificate2 certificate, string hostName, bool checkCertificateRevocationList, out X509Chain chain, out SslPolicyErrors sslPolicyErrors) { chain = null; sslPolicyErrors = SslPolicyErrors.None; // Build the chain. chain = new X509Chain(); chain.ChainPolicy.RevocationMode = checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; // Authenticate the remote party: (e.g. when operating in client mode, authenticate the server). chain.ChainPolicy.ApplicationPolicy.Add(s_serverAuthOid); if (!chain.Build(certificate)) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; } // Verify the hostName matches the certificate. unsafe { var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA(); cppStruct.cbSize = (uint)Marshal.SizeOf <Interop.Crypt32.CERT_CHAIN_POLICY_PARA>(); cppStruct.dwFlags = 0; var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA(); eppStruct.cbSize = (uint)Marshal.SizeOf <Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA>(); eppStruct.dwAuthType = Interop.Crypt32.AuthType.AUTHTYPE_SERVER; cppStruct.pvExtraPolicyPara = &eppStruct; fixed(char *namePtr = hostName) { eppStruct.pwszServerName = namePtr; cppStruct.dwFlags = Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG; var status = new Interop.Crypt32.CERT_CHAIN_POLICY_STATUS(); status.cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_STATUS); if (Interop.Crypt32.CertVerifyCertificateChainPolicy( (IntPtr)Interop.Crypt32.CertChainPolicy.CERT_CHAIN_POLICY_SSL, chain.SafeHandle, ref cppStruct, ref status)) { if (status.dwError == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH) { sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } else { // Failure checking the policy. This is a rare error. We will assume the name check failed. // TODO: Issue #2165. Log this error or perhaps throw an exception instead. sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; } } } }