File: System\Security\Cryptography\X509Certificates\ChainPal.Windows.GetChainStatusInformation.cs
Web Access
Project: src\src\runtime\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Numerics;

namespace System.Security.Cryptography.X509Certificates
{
    internal sealed partial class ChainPal : IDisposable, IChainPal
    {
        private static X509ChainStatus[] GetChainStatusInformation(CertTrustErrorStatus dwStatus)
        {
            if (dwStatus == CertTrustErrorStatus.CERT_TRUST_NO_ERROR)
                return Array.Empty<X509ChainStatus>();

            int count = BitOperations.PopCount((uint)dwStatus);
            X509ChainStatus[] chainStatus = new X509ChainStatus[count];
            int index = 0;

            foreach (X509ChainErrorMapping mapping in s_x509ChainErrorMappings)
            {
                if ((dwStatus & mapping.Win32Flag) != 0)
                {
                    Debug.Assert(index < chainStatus.Length);

                    chainStatus[index].StatusInformation = mapping.Message;
                    chainStatus[index].Status = mapping.ChainStatusFlag;
                    index++;
                    dwStatus &= ~mapping.Win32Flag;
                }
            }

            int shiftCount = 0;
            for (uint bits = (uint)dwStatus; bits != 0; bits >>= 1)
            {
                if ((bits & 0x1) != 0)
                {
                    Debug.Assert(index < chainStatus.Length);

                    chainStatus[index].Status = (X509ChainStatusFlags)(1 << shiftCount);
                    chainStatus[index].StatusInformation = SR.Unknown_Error;
                    index++;
                }
                shiftCount++;
            }

            Debug.Assert(index == chainStatus.Length);

            return chainStatus;
        }

        private readonly struct X509ChainErrorMapping
        {
            public readonly CertTrustErrorStatus Win32Flag;
            public readonly int Win32ErrorCode;
            public readonly X509ChainStatusFlags ChainStatusFlag;
            public readonly string Message;

            public X509ChainErrorMapping(CertTrustErrorStatus win32Flag, int win32ErrorCode, X509ChainStatusFlags chainStatusFlag)
            {
                Win32Flag = win32Flag;
                Win32ErrorCode = win32ErrorCode;
                ChainStatusFlag = chainStatusFlag;
                Message = Interop.Kernel32.GetMessage(win32ErrorCode);
            }
        }

        private static readonly X509ChainErrorMapping[] s_x509ChainErrorMappings = new[]
        {
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_IS_NOT_SIGNATURE_VALID, ErrorCode.TRUST_E_CERT_SIGNATURE, X509ChainStatusFlags.NotSignatureValid),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID, ErrorCode.TRUST_E_CERT_SIGNATURE, X509ChainStatusFlags.CtlNotSignatureValid),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_IS_UNTRUSTED_ROOT, ErrorCode.CERT_E_UNTRUSTEDROOT, X509ChainStatusFlags.UntrustedRoot),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_IS_PARTIAL_CHAIN, ErrorCode.CERT_E_CHAINING, X509ChainStatusFlags.PartialChain),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_IS_REVOKED, ErrorCode.CRYPT_E_REVOKED, X509ChainStatusFlags.Revoked),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_IS_NOT_VALID_FOR_USAGE, ErrorCode.CERT_E_WRONG_USAGE, X509ChainStatusFlags.NotValidForUsage),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE, ErrorCode.CERT_E_WRONG_USAGE, X509ChainStatusFlags.CtlNotValidForUsage),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_IS_NOT_TIME_VALID, ErrorCode.CERT_E_EXPIRED, X509ChainStatusFlags.NotTimeValid),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_CTL_IS_NOT_TIME_VALID, ErrorCode.CERT_E_EXPIRED, X509ChainStatusFlags.CtlNotTimeValid),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_INVALID_NAME_CONSTRAINTS, ErrorCode.CERT_E_INVALID_NAME, X509ChainStatusFlags.InvalidNameConstraints),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT, ErrorCode.CERT_E_INVALID_NAME, X509ChainStatusFlags.HasNotSupportedNameConstraint),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT, ErrorCode.CERT_E_INVALID_NAME, X509ChainStatusFlags.HasNotDefinedNameConstraint),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT, ErrorCode.CERT_E_INVALID_NAME, X509ChainStatusFlags.HasNotPermittedNameConstraint),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT, ErrorCode.CERT_E_INVALID_NAME, X509ChainStatusFlags.HasExcludedNameConstraint),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_INVALID_POLICY_CONSTRAINTS, ErrorCode.CERT_E_INVALID_POLICY, X509ChainStatusFlags.InvalidPolicyConstraints),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY, ErrorCode.CERT_E_INVALID_POLICY, X509ChainStatusFlags.NoIssuanceChainPolicy),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_INVALID_BASIC_CONSTRAINTS, ErrorCode.TRUST_E_BASIC_CONSTRAINTS, X509ChainStatusFlags.InvalidBasicConstraints),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_IS_NOT_TIME_NESTED, ErrorCode.CERT_E_VALIDITYPERIODNESTING, X509ChainStatusFlags.NotTimeNested),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_REVOCATION_STATUS_UNKNOWN, ErrorCode.CRYPT_E_NO_REVOCATION_CHECK, X509ChainStatusFlags.RevocationStatusUnknown),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_IS_OFFLINE_REVOCATION, ErrorCode.CRYPT_E_REVOCATION_OFFLINE, X509ChainStatusFlags.OfflineRevocation),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_IS_EXPLICIT_DISTRUST, ErrorCode.TRUST_E_EXPLICIT_DISTRUST, X509ChainStatusFlags.ExplicitDistrust),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT, ErrorCode.CERT_E_CRITICAL, X509ChainStatusFlags.HasNotSupportedCriticalExtension),
            new X509ChainErrorMapping(CertTrustErrorStatus.CERT_TRUST_HAS_WEAK_SIGNATURE, ErrorCode.CERTSRV_E_WEAK_SIGNATURE_OR_KEY, X509ChainStatusFlags.HasWeakSignature),
        };
    }
}