| | | 1 | | // Licensed to the .NET Foundation under one or more agreements. |
| | | 2 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | | 3 | | |
| | | 4 | | using System.Diagnostics; |
| | | 5 | | using System.Net.Security; |
| | | 6 | | using System.Runtime.InteropServices; |
| | | 7 | | using System.Security.Cryptography; |
| | | 8 | | using System.Security.Cryptography.X509Certificates; |
| | | 9 | | using System.Security.Principal; |
| | | 10 | | using Microsoft.Win32.SafeHandles; |
| | | 11 | | |
| | | 12 | | namespace System.Net |
| | | 13 | | { |
| | | 14 | | internal static partial class CertificateValidation |
| | | 15 | | { |
| | | 16 | | #pragma warning disable IDE0060 |
| | | 17 | | internal static SslPolicyErrors BuildChainAndVerifyProperties(X509Chain chain, X509Certificate2 remoteCertificat |
| | | 18 | | => BuildChainAndVerifyProperties(chain, remoteCertificate, checkCertName, isServer, hostName); |
| | | 19 | | #pragma warning restore IDE0060 |
| | | 20 | | |
| | | 21 | | internal static SslPolicyErrors BuildChainAndVerifyProperties(X509Chain chain, X509Certificate2 remoteCertificat |
| | 0 | 22 | | { |
| | 0 | 23 | | SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None; |
| | | 24 | | |
| | 0 | 25 | | bool chainBuildResult = chain.Build(remoteCertificate); |
| | 0 | 26 | | if (!chainBuildResult // Build failed on handle or on policy. |
| | 0 | 27 | | && chain.SafeHandle!.DangerousGetHandle() == IntPtr.Zero) // Build failed to generate a valid handle. |
| | 0 | 28 | | { |
| | | 29 | | #if NETFRAMEWORK |
| | | 30 | | throw new CryptographicException(Marshal.GetLastWin32Error()); |
| | | 31 | | #else |
| | 0 | 32 | | throw new CryptographicException(Marshal.GetLastPInvokeError()); |
| | | 33 | | #endif |
| | | 34 | | } |
| | | 35 | | |
| | 0 | 36 | | if (checkCertName) |
| | 0 | 37 | | { |
| | | 38 | | unsafe |
| | 0 | 39 | | { |
| | 0 | 40 | | uint status = 0; |
| | | 41 | | |
| | 0 | 42 | | var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA() |
| | 0 | 43 | | { |
| | 0 | 44 | | cbSize = (uint)sizeof(Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA), |
| | 0 | 45 | | // Authenticate the remote party: (e.g. when operating in server mode, authenticate the client). |
| | 0 | 46 | | dwAuthType = isServer ? Interop.Crypt32.AuthType.AUTHTYPE_CLIENT : Interop.Crypt32.AuthType.AUTH |
| | 0 | 47 | | fdwChecks = 0, |
| | 0 | 48 | | pwszServerName = null |
| | 0 | 49 | | }; |
| | | 50 | | |
| | 0 | 51 | | var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA() |
| | 0 | 52 | | { |
| | 0 | 53 | | cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_PARA), |
| | 0 | 54 | | dwFlags = 0, |
| | 0 | 55 | | pvExtraPolicyPara = &eppStruct |
| | 0 | 56 | | }; |
| | | 57 | | |
| | 0 | 58 | | fixed (char* namePtr = hostName) |
| | 0 | 59 | | { |
| | 0 | 60 | | eppStruct.pwszServerName = (ushort*)namePtr; |
| | 0 | 61 | | cppStruct.dwFlags |= |
| | 0 | 62 | | (Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL & |
| | 0 | 63 | | ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG); |
| | | 64 | | |
| | 0 | 65 | | SafeX509ChainHandle chainContext = chain.SafeHandle!; |
| | 0 | 66 | | status = Verify(chainContext, ref cppStruct); |
| | 0 | 67 | | if (status == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH) |
| | 0 | 68 | | { |
| | 0 | 69 | | sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch; |
| | 0 | 70 | | } |
| | 0 | 71 | | } |
| | 0 | 72 | | } |
| | 0 | 73 | | } |
| | | 74 | | |
| | 0 | 75 | | if (!chainBuildResult) |
| | 0 | 76 | | { |
| | 0 | 77 | | sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; |
| | 0 | 78 | | } |
| | | 79 | | |
| | 0 | 80 | | return sslPolicyErrors; |
| | 0 | 81 | | } |
| | | 82 | | |
| | | 83 | | private static unsafe uint Verify(SafeX509ChainHandle chainContext, ref Interop.Crypt32.CERT_CHAIN_POLICY_PARA c |
| | 0 | 84 | | { |
| | 0 | 85 | | Interop.Crypt32.CERT_CHAIN_POLICY_STATUS status = default; |
| | 0 | 86 | | status.cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_STATUS); |
| | | 87 | | |
| | 0 | 88 | | bool errorCode = |
| | 0 | 89 | | Interop.Crypt32.CertVerifyCertificateChainPolicy( |
| | 0 | 90 | | (IntPtr)Interop.Crypt32.CertChainPolicy.CERT_CHAIN_POLICY_SSL, |
| | 0 | 91 | | chainContext, |
| | 0 | 92 | | ref cpp, |
| | 0 | 93 | | ref status); |
| | | 94 | | |
| | 0 | 95 | | if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(chainContext, $"CertVerifyCertificateChainPolicy ret |
| | 0 | 96 | | return status.dwError; |
| | 0 | 97 | | } |
| | | 98 | | } |
| | | 99 | | } |
| | | 100 | | |