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)) {
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); }