Пример #1
0
            private static X509ChainStatus ValidationErrorToChainStatus(Interop.AndroidCrypto.ValidationError error)
            {
                X509ChainStatusFlags statusFlags = (X509ChainStatusFlags)error.Status;

                Debug.Assert(statusFlags != X509ChainStatusFlags.NoError);

                return(new X509ChainStatus
                {
                    Status = statusFlags,
                    StatusInformation = Marshal.PtrToStringUni(error.Message)
                });
            }
Пример #2
0
            private static Dictionary <int, List <X509ChainStatus> > GetStatusByIndex(SafeX509ChainContextHandle ctx)
            {
                var statusByIndex = new Dictionary <int, List <X509ChainStatus> >();

                Interop.AndroidCrypto.ValidationError[] errors = Interop.AndroidCrypto.X509ChainGetErrors(ctx);
                for (int i = 0; i < errors.Length; i++)
                {
                    Interop.AndroidCrypto.ValidationError error = errors[i];
                    X509ChainStatus chainStatus = ValidationErrorToChainStatus(error);
                    Marshal.FreeHGlobal(error.Message);

                    if (!statusByIndex.ContainsKey(error.Index))
                    {
                        statusByIndex.Add(error.Index, new List <X509ChainStatus>());
                    }

                    statusByIndex[error.Index].Add(chainStatus);
                }

                return(statusByIndex);
            }
Пример #3
0
            internal void Evaluate(
                DateTime verificationTime,
                OidCollection?applicationPolicy,
                OidCollection?certificatePolicy,
                X509RevocationMode revocationMode,
                X509RevocationFlag revocationFlag)
            {
                Debug.Assert(_chainContext != null);

                long timeInMsFromUnixEpoch = new DateTimeOffset(verificationTime).ToUnixTimeMilliseconds();

                _isValid = Interop.AndroidCrypto.X509ChainBuild(_chainContext, timeInMsFromUnixEpoch);
                if (!_isValid)
                {
                    // Android always validates name, time, signature, and trusted root.
                    // There is no way bypass that validation and build a path.
                    ChainElements = Array.Empty <X509ChainElement>();

                    Interop.AndroidCrypto.ValidationError[] errors = Interop.AndroidCrypto.X509ChainGetErrors(_chainContext);
                    var chainStatus = new X509ChainStatus[errors.Length];
                    for (int i = 0; i < errors.Length; i++)
                    {
                        Interop.AndroidCrypto.ValidationError error = errors[i];
                        chainStatus[i] = ValidationErrorToChainStatus(error);
                        Marshal.FreeHGlobal(error.Message);
                    }

                    ChainStatus = chainStatus;
                    return;
                }

                byte checkedRevocation;
                int  res = Interop.AndroidCrypto.X509ChainValidate(_chainContext, revocationMode, revocationFlag, out checkedRevocation);

                if (res != 1)
                {
                    throw new CryptographicException();
                }

                X509Certificate2[]     certs         = Interop.AndroidCrypto.X509ChainGetCertificates(_chainContext);
                List <X509ChainStatus> overallStatus = new List <X509ChainStatus>();

                List <X509ChainStatus>[] statuses = new List <X509ChainStatus> [certs.Length];

                // Android will stop checking after the first error it hits, so we track the first
                // instances of revocation and non-revocation errors to fix-up the status of elements
                // beyond the first error
                int firstNonRevocationErrorIndex = -1;
                int firstRevocationErrorIndex    = -1;
                Dictionary <int, List <X509ChainStatus> > errorsByIndex = GetStatusByIndex(_chainContext);

                foreach (int index in errorsByIndex.Keys)
                {
                    List <X509ChainStatus> errors = errorsByIndex[index];
                    for (int i = 0; i < errors.Count; i++)
                    {
                        X509ChainStatus status = errors[i];
                        AddUniqueStatus(overallStatus, ref status);
                    }

                    // -1 indicates that error is not tied to a specific index
                    if (index != -1)
                    {
                        statuses[index] = errorsByIndex[index];
                        if (errorsByIndex[index].Exists(s => s.Status == X509ChainStatusFlags.Revoked || s.Status == X509ChainStatusFlags.RevocationStatusUnknown))
                        {
                            firstRevocationErrorIndex = Math.Max(index, firstRevocationErrorIndex);
                        }
                        else
                        {
                            firstNonRevocationErrorIndex = Math.Max(index, firstNonRevocationErrorIndex);
                        }
                    }
                }

                if (firstNonRevocationErrorIndex > 0)
                {
                    // Assign PartialChain to everything from the first non-revocation error to the end certificate
                    X509ChainStatus partialChainStatus = new X509ChainStatus
                    {
                        Status            = X509ChainStatusFlags.PartialChain,
                        StatusInformation = SR.Chain_PartialChain,
                    };
                    AddStatusFromIndexToEndCertificate(firstNonRevocationErrorIndex - 1, ref partialChainStatus, statuses, overallStatus);
                }

                if (firstRevocationErrorIndex > 0)
                {
                    // Assign RevocationStatusUnknown to everything from the first revocation error to the end certificate
                    X509ChainStatus revocationUnknownStatus = new X509ChainStatus
                    {
                        Status            = X509ChainStatusFlags.RevocationStatusUnknown,
                        StatusInformation = SR.Chain_RevocationStatusUnknown,
                    };
                    AddStatusFromIndexToEndCertificate(firstRevocationErrorIndex - 1, ref revocationUnknownStatus, statuses, overallStatus);
                }

                if (revocationMode != X509RevocationMode.NoCheck && checkedRevocation == 0)
                {
                    // Revocation checking was requested, but not performed (due to basic validation failing)
                    // Assign RevocationStatusUnknown to everything
                    X509ChainStatus revocationUnknownStatus = new X509ChainStatus
                    {
                        Status            = X509ChainStatusFlags.RevocationStatusUnknown,
                        StatusInformation = SR.Chain_RevocationStatusUnknown,
                    };
                    AddStatusFromIndexToEndCertificate(statuses.Length - 1, ref revocationUnknownStatus, statuses, overallStatus);
                }

                if (!IsPolicyMatch(certs, applicationPolicy, certificatePolicy))
                {
                    // Assign NotValidForUsage to everything
                    X509ChainStatus policyFailStatus = new X509ChainStatus
                    {
                        Status            = X509ChainStatusFlags.NotValidForUsage,
                        StatusInformation = SR.Chain_NoPolicyMatch,
                    };
                    AddStatusFromIndexToEndCertificate(statuses.Length - 1, ref policyFailStatus, statuses, overallStatus);
                }

                X509ChainElement[] elements = new X509ChainElement[certs.Length];
                for (int i = 0; i < certs.Length; i++)
                {
                    X509ChainStatus[] elementStatus = statuses[i] == null?Array.Empty <X509ChainStatus>() : statuses[i].ToArray();

                    elements[i] = new X509ChainElement(certs[i], elementStatus, string.Empty);
                }

                ChainElements = elements;
                ChainStatus   = overallStatus.ToArray();
            }