Beispiel #1
0
        async Task <ArcValidationResult> VerifyAsync(FormatOptions options, MimeMessage message, bool doAsync, CancellationToken cancellationToken)
        {
            const ArcValidationErrors ArcSealCvParamErrors = ArcValidationErrors.InvalidArcSealChainValidationValue | ArcValidationErrors.MissingArcSealChainValidationValue;

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            var result = new ArcValidationResult();

            switch (GetArcHeaderSets(message, false, out ArcHeaderSet[] sets, out int count, out var errors))
            {
Beispiel #2
0
        internal static ArcSignatureValidationResult GetArcHeaderSets(MimeMessage message, bool throwOnError, out ArcHeaderSet[] sets, out int count, out ArcValidationErrors errors)
        {
            ArcHeaderSet set;

            errors = ArcValidationErrors.None;
            sets   = new ArcHeaderSet[50];
            count  = 0;

            for (int i = 0; i < message.Headers.Count; i++)
            {
                Dictionary <string, string> parameters = null;
                var    header   = message.Headers[i];
                int    instance = 0;
                string value;

                switch (header.Id)
                {
                case HeaderId.ArcAuthenticationResults:
                    if (!AuthenticationResults.TryParse(header.RawValue, out AuthenticationResults authres))
                    {
                        if (throwOnError)
                        {
                            throw new FormatException("Invalid ARC-Authentication-Results header.");
                        }

                        errors |= ArcValidationErrors.InvalidArcAuthenticationResults;
                        break;
                    }

                    if (!authres.Instance.HasValue)
                    {
                        if (throwOnError)
                        {
                            throw new FormatException("Missing instance tag in ARC-Authentication-Results header.");
                        }

                        errors |= ArcValidationErrors.InvalidArcAuthenticationResults;
                        break;
                    }

                    instance = authres.Instance.Value;

                    if (instance < 1 || instance > 50)
                    {
                        if (throwOnError)
                        {
                            throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Invalid instance tag in ARC-Authentication-Results header: i={0}", instance));
                        }

                        errors  |= ArcValidationErrors.InvalidArcAuthenticationResults;
                        instance = 0;
                        break;
                    }
                    break;

                case HeaderId.ArcMessageSignature:
                case HeaderId.ArcSeal:
                    try {
                        parameters = ParseParameterTags(header.Id, header.Value);
                    } catch {
                        if (throwOnError)
                        {
                            throw;
                        }

                        if (header.Id == HeaderId.ArcMessageSignature)
                        {
                            errors |= ArcValidationErrors.InvalidArcMessageSignature;
                        }
                        else
                        {
                            errors |= ArcValidationErrors.InvalidArcSeal;
                        }

                        break;
                    }

                    if (!parameters.TryGetValue("i", out value))
                    {
                        if (throwOnError)
                        {
                            throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Missing instance tag in {0} header.", header.Id.ToHeaderName()));
                        }

                        if (header.Id == HeaderId.ArcMessageSignature)
                        {
                            errors |= ArcValidationErrors.InvalidArcMessageSignature;
                        }
                        else
                        {
                            errors |= ArcValidationErrors.InvalidArcSeal;
                        }

                        break;
                    }

                    if (!int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out instance) || instance < 1 || instance > 50)
                    {
                        if (throwOnError)
                        {
                            throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Invalid instance tag in {0} header: i={1}", header.Id.ToHeaderName(), value));
                        }

                        if (header.Id == HeaderId.ArcMessageSignature)
                        {
                            errors |= ArcValidationErrors.InvalidArcMessageSignature;
                        }
                        else
                        {
                            errors |= ArcValidationErrors.InvalidArcSeal;
                        }

                        instance = 0;
                        break;
                    }
                    break;
                }

                if (instance == 0)
                {
                    continue;
                }

                set = sets[instance - 1];
                if (set == null)
                {
                    sets[instance - 1] = set = new ArcHeaderSet();
                }

                if (!set.Add(header, parameters))
                {
                    if (throwOnError)
                    {
                        throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Duplicate {0} header for i={1}", header.Id.ToHeaderName(), instance));
                    }

                    switch (header.Id)
                    {
                    case HeaderId.ArcAuthenticationResults:
                        errors |= ArcValidationErrors.DuplicateArcAuthenticationResults;
                        break;

                    case HeaderId.ArcMessageSignature:
                        errors |= ArcValidationErrors.DuplicateArcMessageSignature;
                        break;

                    case HeaderId.ArcSeal:
                        errors |= ArcValidationErrors.DuplicateArcSeal;
                        break;
                    }
                }

                if (instance > count)
                {
                    count = instance;
                }
            }

            if (count == 0)
            {
                // there are no ARC sets
                return(ArcSignatureValidationResult.None);
            }

            // verify that all ARC sets are complete
            for (int i = 0; i < count; i++)
            {
                set = sets[i];

                if (set == null)
                {
                    if (throwOnError)
                    {
                        throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Missing ARC headers for i={0}", i + 1));
                    }

                    if ((errors & ArcValidationErrors.InvalidArcAuthenticationResults) == 0)
                    {
                        errors |= ArcValidationErrors.MissingArcAuthenticationResults;
                    }
                    if ((errors & ArcValidationErrors.InvalidArcMessageSignature) == 0)
                    {
                        errors |= ArcValidationErrors.MissingArcMessageSignature;
                    }
                    if ((errors & ArcValidationErrors.InvalidArcSeal) == 0)
                    {
                        errors |= ArcValidationErrors.MissingArcSeal;
                    }
                    continue;
                }

                if (set.ArcAuthenticationResult == null)
                {
                    if (throwOnError)
                    {
                        throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Missing ARC-Authentication-Results header for i={0}", i + 1));
                    }

                    if ((errors & ArcValidationErrors.InvalidArcAuthenticationResults) == 0)
                    {
                        errors |= ArcValidationErrors.MissingArcAuthenticationResults;
                    }
                }

                if (set.ArcMessageSignature == null)
                {
                    if (throwOnError)
                    {
                        throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Missing ARC-Message-Signature header for i={0}", i + 1));
                    }

                    if ((errors & ArcValidationErrors.InvalidArcMessageSignature) == 0)
                    {
                        errors |= ArcValidationErrors.MissingArcMessageSignature;
                    }
                }

                if (set.ArcSeal == null)
                {
                    if (throwOnError)
                    {
                        throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Missing ARC-Seal header for i={0}", i + 1));
                    }

                    if ((errors & ArcValidationErrors.InvalidArcSeal) == 0)
                    {
                        errors |= ArcValidationErrors.MissingArcSeal;
                    }
                    continue;
                }

                if (!set.ArcSealParameters.TryGetValue("cv", out string cv))
                {
                    if (throwOnError)
                    {
                        throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Missing chain validation tag in ARC-Seal header for i={0}.", i + 1));
                    }

                    errors |= ArcValidationErrors.MissingArcSealChainValidationValue;
                    continue;
                }

                // The "cv" value for all ARC-Seal header fields MUST NOT be
                // "fail". For ARC Sets with instance values > 1, the values
                // MUST be "pass". For the ARC Set with instance value = 1, the
                // value MUST be "none".
                if (!cv.Equals(i == 0 ? "none" : "pass", StringComparison.Ordinal))
                {
                    errors |= ArcValidationErrors.InvalidArcSealChainValidationValue;
                }
            }

            return(errors == ArcValidationErrors.None ? ArcSignatureValidationResult.Pass : ArcSignatureValidationResult.Fail);
        }