< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.IdentityModel.Selectors.X509CertificateValidator
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/IdentityModel/Selectors/X509CertificateValidator.cs
Line coverage
23%
Covered lines: 22
Uncovered lines: 73
Coverable lines: 95
Total lines: 288
Line coverage: 23.1%
Branch coverage
16%
Covered branches: 7
Total branches: 42
Branch coverage: 16.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
CreateChainTrustValidator(...)50%2266.66%
CreatePeerOrChainTrustValidator(...)50%2266.66%
Validate(...)50%2266.66%
Validate(...)0%440%
StoreContainsCertificate(...)100%110%
TryValidate(...)0%880%
.ctor()100%1125%
.ctor(...)100%11100%
Validate(...)0%660%
GetChainStatusInformation(...)0%440%
.ctor()100%110%
.ctor(...)100%11100%
Validate(...)0%440%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/IdentityModel/Selectors/X509CertificateValidator.cs

#LineLine coverage
 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
 4using System;
 5using System.Security.Cryptography.X509Certificates;
 6using System.Text;
 7using CoreWCF.IdentityModel.Tokens;
 8using CoreWCF.Security;
 9
 10namespace CoreWCF.IdentityModel.Selectors
 11{
 12    public abstract class X509CertificateValidator
 13    {
 14        internal const uint CAPI_CERT_CHAIN_POLICY_NT_AUTH = 6;
 15        private static X509CertificateValidator s_peerTrust;
 16        private static X509CertificateValidator s_chainTrust;
 17        private static X509CertificateValidator s_ntAuthChainTrust;
 18        private static X509CertificateValidator s_peerOrChainTrust;
 19        private static X509CertificateValidator s_none;
 20
 21        public static X509CertificateValidator None
 22        {
 23            get
 24            {
 625                if (s_none == null)
 26                {
 427                    s_none = new NoneX509CertificateValidator();
 28                }
 29
 630                return s_none;
 31            }
 32        }
 33
 34        public static X509CertificateValidator PeerTrust
 35        {
 36            get
 37            {
 238                if (s_peerTrust == null)
 39                {
 240                    s_peerTrust = new PeerTrustValidator();
 41                }
 42
 243                return s_peerTrust;
 44            }
 45        }
 46
 47        public static X509CertificateValidator ChainTrust
 48        {
 49            get
 50            {
 051                if (s_chainTrust == null)
 52                {
 053                    s_chainTrust = new ChainTrustValidator();
 54                }
 55
 056                return s_chainTrust;
 57            }
 58        }
 59
 60        // TODO: Consider creating platform specific package which contains windows only implementations such as NTAuthC
 61        internal static X509CertificateValidator NTAuthChainTrust
 62        {
 63            get
 64            {
 065                if (s_ntAuthChainTrust == null)
 66                {
 067                    s_ntAuthChainTrust = new ChainTrustValidator(false, null, CAPI_CERT_CHAIN_POLICY_NT_AUTH);
 68                }
 69
 070                return s_ntAuthChainTrust;
 71            }
 72        }
 73
 74        public static X509CertificateValidator PeerOrChainTrust
 75        {
 76            get
 77            {
 078                if (s_peerOrChainTrust == null)
 79                {
 080                    s_peerOrChainTrust = new PeerOrChainTrustValidator();
 81                }
 82
 083                return s_peerOrChainTrust;
 84            }
 85        }
 86
 87        public static X509CertificateValidator CreateChainTrustValidator(bool useMachineContext, X509ChainPolicy chainPo
 88        {
 1389            if (chainPolicy == null)
 90            {
 091                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(chainPolicy));
 92            }
 93
 1394            return new ChainTrustValidator(useMachineContext, chainPolicy, X509CertificateChain.DefaultChainPolicyOID);
 95        }
 96
 97        public static X509CertificateValidator CreatePeerOrChainTrustValidator(bool useMachineContext, X509ChainPolicy c
 98        {
 299            if (chainPolicy == null)
 100            {
 0101                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(chainPolicy));
 102            }
 103
 2104            return new PeerOrChainTrustValidator(useMachineContext, chainPolicy);
 105        }
 106
 107        public abstract void Validate(X509Certificate2 certificate);
 108
 109        private class NoneX509CertificateValidator : X509CertificateValidator
 110        {
 111            public override void Validate(X509Certificate2 certificate)
 112            {
 32113                if (certificate == null)
 114                {
 0115                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(certificate));
 116                }
 32117            }
 118        }
 119
 120        private class PeerTrustValidator : X509CertificateValidator
 121        {
 122            public override void Validate(X509Certificate2 certificate)
 123            {
 0124                if (certificate == null)
 125                {
 0126                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(certificate));
 127                }
 128
 0129                if (!TryValidate(certificate, out Exception exception))
 130                {
 0131                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
 132                }
 0133            }
 134
 135            private static bool StoreContainsCertificate(StoreName storeName, X509Certificate2 certificate)
 136            {
 0137                X509Store store = new X509Store(storeName, StoreLocation.CurrentUser);
 0138                X509Certificate2Collection certificates = null;
 139                try
 140                {
 0141                    store.Open(OpenFlags.ReadOnly);
 0142                    certificates = store.Certificates.Find(X509FindType.FindByThumbprint, certificate.Thumbprint, false)
 0143                    return certificates.Count > 0;
 144                }
 145                finally
 146                {
 0147                    SecurityUtils.ResetAllCertificates(certificates);
 0148                    store.Close();
 0149                }
 0150            }
 151
 152            internal bool TryValidate(X509Certificate2 certificate, out Exception exception)
 153            {
 154                // Checklist
 155                // 1) time validity of cert
 156                // 2) in trusted people store
 157                // 3) not in disallowed store
 158
 159                // The following code could be written as:
 160                // DateTime now = DateTime.UtcNow;
 161                // if (now > certificate.NotAfter.ToUniversalTime() || now < certificate.NotBefore.ToUniversalTime())
 162                //
 163                // this is because X509Certificate2.xxx doesn't return UT.  However this would be a SMALL perf hit.
 164                // I put a DebugAssert so that this will ensure that the we are compatible with the CLR we shipped with
 165
 0166                DateTime now = DateTime.Now;
 167                DiagnosticUtility.DebugAssert(now.Kind == certificate.NotAfter.Kind && now.Kind == certificate.NotBefore
 168
 0169                if (now > certificate.NotAfter || now < certificate.NotBefore)
 170                {
 0171                    exception = new SecurityTokenValidationException(SR.Format(SR.X509InvalidUsageTime,
 0172                        SecurityUtils.GetCertificateId(certificate), now, certificate.NotBefore, certificate.NotAfter));
 0173                    return false;
 174                }
 175
 0176                if (!StoreContainsCertificate(StoreName.TrustedPeople, certificate))
 177                {
 0178                    exception = new SecurityTokenValidationException(SR.Format(SR.X509IsNotInTrustedStore,
 0179                        SecurityUtils.GetCertificateId(certificate)));
 0180                    return false;
 181                }
 182
 0183                if (StoreContainsCertificate(StoreName.Disallowed, certificate))
 184                {
 0185                    exception = new SecurityTokenValidationException(SR.Format(SR.X509IsInUntrustedStore,
 0186                        SecurityUtils.GetCertificateId(certificate)));
 0187                    return false;
 188                }
 0189                exception = null;
 0190                return true;
 191            }
 192        }
 193
 194        private class ChainTrustValidator : X509CertificateValidator
 195        {
 196            private readonly bool _useMachineContext;
 197            private readonly X509ChainPolicy _chainPolicy;
 13198            private readonly uint _chainPolicyOID = X509CertificateChain.DefaultChainPolicyOID;
 199
 0200            public ChainTrustValidator()
 201            {
 0202                _chainPolicy = null;
 0203            }
 204
 13205            public ChainTrustValidator(bool useMachineContext, X509ChainPolicy chainPolicy, uint chainPolicyOID)
 206            {
 13207                _useMachineContext = useMachineContext;
 13208                _chainPolicy = chainPolicy;
 13209                _chainPolicyOID = chainPolicyOID;
 13210            }
 211
 212            public override void Validate(X509Certificate2 certificate)
 213            {
 0214                if (certificate == null)
 215                {
 0216                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(certificate));
 217                }
 218
 0219                X509Chain chain = new X509Chain();
 0220                if (_chainPolicy != null)
 221                {
 0222                    chain.ChainPolicy = _chainPolicy;
 223                }
 224
 0225                if (!chain.Build(certificate))
 226                {
 0227                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenValidationException(SR.Fo
 0228                        SecurityUtils.GetCertificateId(certificate), GetChainStatusInformation(chain.ChainStatus))));
 229                }
 0230            }
 231
 232            private static string GetChainStatusInformation(X509ChainStatus[] chainStatus)
 233            {
 0234                if (chainStatus != null)
 235                {
 0236                    StringBuilder error = new StringBuilder(128);
 0237                    for (int i = 0; i < chainStatus.Length; ++i)
 238                    {
 0239                        error.Append(chainStatus[i].StatusInformation);
 0240                        error.Append(" ");
 241                    }
 0242                    return error.ToString();
 243                }
 0244                return string.Empty;
 245            }
 246        }
 247
 248        private class PeerOrChainTrustValidator : X509CertificateValidator
 249        {
 250            private readonly X509CertificateValidator _chain;
 251            private readonly PeerTrustValidator _peer;
 252
 0253            public PeerOrChainTrustValidator()
 254            {
 0255                _chain = ChainTrust;
 0256                _peer = (PeerTrustValidator)PeerTrust;
 0257            }
 258
 2259            public PeerOrChainTrustValidator(bool useMachineContext, X509ChainPolicy chainPolicy)
 260            {
 2261                _chain = CreateChainTrustValidator(useMachineContext, chainPolicy);
 2262                _peer = (PeerTrustValidator)PeerTrust;
 2263            }
 264
 265            public override void Validate(X509Certificate2 certificate)
 266            {
 0267                if (certificate == null)
 268                {
 0269                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(certificate));
 270                }
 271
 0272                if (_peer.TryValidate(certificate, out Exception exception))
 273                {
 0274                    return;
 275                }
 276
 277                try
 278                {
 0279                    _chain.Validate(certificate);
 0280                }
 0281                catch (SecurityTokenValidationException ex)
 282                {
 0283                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenValidationException(excep
 284                }
 0285            }
 286        }
 287    }
 288}