private uint[] GetChainErrors(string hostName, X509Chain chain, ref bool fatalError) { fatalError = false; SafeFreeCertChain chainContext= new SafeFreeCertChain(chain.ChainContext); ArrayList certificateProblems = new ArrayList(); unsafe { uint status = 0; ChainPolicyParameter cppStruct = new ChainPolicyParameter(); cppStruct.cbSize = ChainPolicyParameter.StructSize; cppStruct.dwFlags = 0; SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = new SSL_EXTRA_CERT_CHAIN_POLICY_PARA(false); cppStruct.pvExtraPolicyPara = &eppStruct; fixed (char* namePtr = hostName) { if (ServicePointManager.CheckCertificateName){ eppStruct.pwszServerName = namePtr; } while (true) { status = VerifyChainPolicy(chainContext, ref cppStruct); uint ignoreErrorMask = (uint)MapErrorCode(status); certificateProblems.Add(status); if (status == 0) { // No more problems with the certificate break; // Then break out of the callback loop } if (ignoreErrorMask == 0) { // Unrecognized error encountered fatalError = true; break; } else { cppStruct.dwFlags |= ignoreErrorMask; if ((CertificateProblem)status == CertificateProblem.CertCN_NO_MATCH && ServicePointManager.CheckCertificateName) { eppStruct.fdwChecks = IgnoreUnmatchedCN; } } } } } return (uint[]) certificateProblems.ToArray(typeof(uint)); }
internal unsafe bool VerifyRemoteCertificate(RemoteCertValidationCallback remoteCertValidationCallback) { SslPolicyErrors none = SslPolicyErrors.None; bool flag = false; X509Chain chain = null; X509Certificate2 remoteCertificate = null; try { X509Certificate2Collection certificates; remoteCertificate = this.GetRemoteCertificate(out certificates); this.m_IsRemoteCertificateAvailable = remoteCertificate != null; if (remoteCertificate == null) { none |= SslPolicyErrors.RemoteCertificateNotAvailable; } else { chain = new X509Chain { ChainPolicy = { RevocationMode = this.m_CheckCertRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, RevocationFlag = X509RevocationFlag.ExcludeRoot } }; if (certificates != null) { chain.ChainPolicy.ExtraStore.AddRange(certificates); } if (!chain.Build(remoteCertificate) && (chain.ChainContext == IntPtr.Zero)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } if (this.m_CheckCertName) { ChainPolicyParameter cpp = new ChainPolicyParameter { cbSize = ChainPolicyParameter.StructSize, dwFlags = 0 }; SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_extra_cert_chain_policy_para = new SSL_EXTRA_CERT_CHAIN_POLICY_PARA(this.IsServer); cpp.pvExtraPolicyPara = &ssl_extra_cert_chain_policy_para; fixed(char *str = ((char *)this.m_HostName)) { char *chPtr = str; ssl_extra_cert_chain_policy_para.pwszServerName = chPtr; cpp.dwFlags |= 0xfbf; SafeFreeCertChain chainContext = new SafeFreeCertChain(chain.ChainContext); if (PolicyWrapper.VerifyChainPolicy(chainContext, ref cpp) == 0x800b010f) { none |= SslPolicyErrors.RemoteCertificateNameMismatch; } } } X509ChainStatus[] chainStatus = chain.ChainStatus; if ((chainStatus != null) && (chainStatus.Length != 0)) { none |= SslPolicyErrors.RemoteCertificateChainErrors; } } if (remoteCertValidationCallback != null) { flag = remoteCertValidationCallback(this.m_HostName, remoteCertificate, chain, none); } else if ((none == SslPolicyErrors.RemoteCertificateNotAvailable) && !this.m_RemoteCertRequired) { flag = true; } else { flag = none == SslPolicyErrors.None; } if (!Logging.On) { return(flag); } if (none != SslPolicyErrors.None) { Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_remote_cert_has_errors")); if ((none & SslPolicyErrors.RemoteCertificateNotAvailable) != SslPolicyErrors.None) { Logging.PrintInfo(Logging.Web, this, "\t" + SR.GetString("net_log_remote_cert_not_available")); } if ((none & SslPolicyErrors.RemoteCertificateNameMismatch) != SslPolicyErrors.None) { Logging.PrintInfo(Logging.Web, this, "\t" + SR.GetString("net_log_remote_cert_name_mismatch")); } if ((none & SslPolicyErrors.RemoteCertificateChainErrors) != SslPolicyErrors.None) { foreach (X509ChainStatus status in chain.ChainStatus) { Logging.PrintInfo(Logging.Web, this, "\t" + status.StatusInformation); } } } if (flag) { if (remoteCertValidationCallback != null) { Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_remote_cert_user_declared_valid")); return(flag); } Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_remote_cert_has_no_errors")); return(flag); } if (remoteCertValidationCallback != null) { Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_remote_cert_user_declared_invalid")); } } finally { if (chain != null) { chain.Reset(); } if (remoteCertificate != null) { remoteCertificate.Reset(); } } return(flag); }
internal static uint VerifyChainPolicy(SafeFreeCertChain chainContext, ref ChainPolicyParameter cpp) { GlobalLog.Enter("PolicyWrapper::VerifyChainPolicy", "chainContext="+ chainContext + ", options="+String.Format("0x{0:x}", cpp.dwFlags)); ChainPolicyStatus status = new ChainPolicyStatus(); status.cbSize = ChainPolicyStatus.StructSize; int errorCode = UnsafeNclNativeMethods.NativePKI.CertVerifyCertificateChainPolicy( (IntPtr) ChainPolicyType.SSL, chainContext, ref cpp, ref status); GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() CertVerifyCertificateChainPolicy returned: " + errorCode); #if TRAVE GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() error code: " + status.dwError+String.Format(" [0x{0:x8}", status.dwError) + " " + SecureChannel.MapSecurityStatus(status.dwError) + "]"); #endif GlobalLog.Leave("PolicyWrapper::VerifyChainPolicy", status.dwError.ToString()); return status.dwError; }