/// <summary> /// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapLiteral"/> class. /// </summary> /// <remarks> /// Creates a new <see cref="MailKit.Net.Imap.ImapLiteral"/>. /// </remarks> /// <param name="options">The formatting options.</param> /// <param name="literal">The literal.</param> /// <param name="action">The progress update action.</param> public ImapLiteral(FormatOptions options, object literal, Action <int> action = null) { format = options.Clone(); format.NewLineFormat = NewLineFormat.Dos; update = action; if (literal is MimeMessage) { Type = ImapLiteralType.MimeMessage; } else if (literal is Stream) { Type = ImapLiteralType.Stream; } else if (literal is string) { literal = Encoding.UTF8.GetBytes((string)literal); Type = ImapLiteralType.String; } else if (literal is byte[]) { Type = ImapLiteralType.String; } else { throw new ArgumentException("Unknown literal type"); } Literal = literal; }
async Task ArcSignAsync(FormatOptions options, MimeMessage message, IList <string> headers, bool doAsync, CancellationToken cancellationToken) { ArcVerifier.GetArcHeaderSets(message, true, out ArcHeaderSet[] sets, out int count, out var errors); AuthenticationResults authres; int instance = count + 1; string cv; // do not sign if there is already a failed/invalid ARC-Seal. if (count > 0 && (errors & ArcValidationErrors.InvalidArcSealChainValidationValue) != 0) { return; } options = options.Clone(); options.NewLineFormat = NewLineFormat.Dos; options.EnsureNewLine = true; if (doAsync) { authres = await GenerateArcAuthenticationResultsAsync(options, message, cancellationToken).ConfigureAwait(false); } else { authres = GenerateArcAuthenticationResults(options, message, cancellationToken); } if (authres == null) { return; } authres.Instance = instance; var aar = new Header(HeaderId.ArcAuthenticationResults, authres.ToString()); cv = "none"; if (count > 0) { cv = "pass"; foreach (var method in authres.Results) { if (method.Method.Equals("arc", StringComparison.OrdinalIgnoreCase)) { cv = method.Result; break; } } } var t = GetTimestamp(); var ams = GenerateArcMessageSignature(options, message, instance, t, headers); var seal = GenerateArcSeal(options, instance, cv, t, sets, count, aar, ams); message.Headers.Insert(0, aar); message.Headers.Insert(0, ams); message.Headers.Insert(0, seal); }
/// <summary> /// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapLiteral"/> class. /// </summary> /// <remarks> /// Creates a new <see cref="MailKit.Net.Imap.ImapLiteral"/>. /// </remarks> /// <param name="options">The formatting options.</param> /// <param name="literal">The literal.</param> public ImapLiteral(FormatOptions options, byte[] literal) { format = options.Clone(); format.NewLineFormat = NewLineFormat.Dos; Type = ImapLiteralType.String; Literal = literal; }
async Task <bool> VerifyArcSealAsync(FormatOptions options, ArcHeaderSet[] sets, int i, bool doAsync, CancellationToken cancellationToken) { DkimSignatureAlgorithm algorithm; AsymmetricKeyParameter key; string d, s, q, b; ValidateArcSealParameters(sets[i].ArcSealParameters, out algorithm, out d, out s, out q, out b); if (!IsEnabled(algorithm)) { return(false); } if (doAsync) { key = await PublicKeyLocator.LocatePublicKeyAsync(q, d, s, cancellationToken).ConfigureAwait(false); } else { key = PublicKeyLocator.LocatePublicKey(q, d, s, cancellationToken); } if ((key is RsaKeyParameters rsa) && rsa.Modulus.BitLength < MinimumRsaKeyLength) { return(false); } options = options.Clone(); options.NewLineFormat = NewLineFormat.Dos; using (var stream = new DkimSignatureStream(CreateVerifyContext(algorithm, key))) { using (var filtered = new FilteredStream(stream)) { filtered.Add(options.CreateNewLineFilter()); for (int j = 0; j < i; j++) { WriteHeaderRelaxed(options, filtered, sets[j].ArcAuthenticationResult, false); WriteHeaderRelaxed(options, filtered, sets[j].ArcMessageSignature, false); WriteHeaderRelaxed(options, filtered, sets[j].ArcSeal, false); } WriteHeaderRelaxed(options, filtered, sets[i].ArcAuthenticationResult, false); WriteHeaderRelaxed(options, filtered, sets[i].ArcMessageSignature, false); // now include the ARC-Seal header that we are verifying, // but only after removing the "b=" signature value. var seal = GetSignedSignatureHeader(sets[i].ArcSeal); WriteHeaderRelaxed(options, filtered, seal, true); filtered.Flush(); } return(stream.VerifySignature(b)); } }
/// <summary> /// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapLiteral"/> class. /// </summary> /// <remarks> /// Creates a new <see cref="MailKit.Net.Imap.ImapLiteral"/>. /// </remarks> /// <param name="options">The formatting options.</param> /// <param name="literal">The literal.</param> /// <param name="action">The progress update action.</param> public ImapLiteral(FormatOptions options, MimeMessage literal, Action <int> action = null) { format = options.Clone(); format.NewLineFormat = NewLineFormat.Dos; update = action; Type = ImapLiteralType.MimeMessage; Literal = literal; }
async Task <bool> VerifyArcMessageSignatureAsync(FormatOptions options, MimeMessage message, Header arcSignature, Dictionary <string, string> parameters, bool doAsync, CancellationToken cancellationToken) { DkimCanonicalizationAlgorithm headerAlgorithm, bodyAlgorithm; DkimSignatureAlgorithm signatureAlgorithm; AsymmetricKeyParameter key; string d, s, q, bh, b; string[] headers; int maxLength; ValidateArcMessageSignatureParameters(parameters, out signatureAlgorithm, out headerAlgorithm, out bodyAlgorithm, out d, out s, out q, out headers, out bh, out b, out maxLength); if (!IsEnabled(signatureAlgorithm)) { return(false); } options = options.Clone(); options.NewLineFormat = NewLineFormat.Dos; // first check the body hash (if that's invalid, then the entire signature is invalid) if (!VerifyBodyHash(options, message, signatureAlgorithm, bodyAlgorithm, maxLength, bh)) { return(false); } if (doAsync) { key = await PublicKeyLocator.LocatePublicKeyAsync(q, d, s, cancellationToken).ConfigureAwait(false); } else { key = PublicKeyLocator.LocatePublicKey(q, d, s, cancellationToken); } if ((key is RsaKeyParameters rsa) && rsa.Modulus.BitLength < MinimumRsaKeyLength) { return(false); } return(VerifySignature(options, message, arcSignature, signatureAlgorithm, key, headers, headerAlgorithm, b)); }
async Task <bool> VerifyAsync(FormatOptions options, MimeMessage message, Header dkimSignature, bool doAsync, CancellationToken cancellationToken) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } if (dkimSignature == null) { throw new ArgumentNullException(nameof(dkimSignature)); } if (dkimSignature.Id != HeaderId.DkimSignature) { throw new ArgumentException("The signature parameter MUST be a DKIM-Signature header.", nameof(dkimSignature)); } var parameters = ParseParameterTags(dkimSignature.Id, dkimSignature.Value); DkimCanonicalizationAlgorithm headerAlgorithm, bodyAlgorithm; DkimSignatureAlgorithm signatureAlgorithm; AsymmetricKeyParameter key; string d, s, q, bh, b; string[] headers; int maxLength; ValidateDkimSignatureParameters(parameters, out signatureAlgorithm, out headerAlgorithm, out bodyAlgorithm, out d, out s, out q, out headers, out bh, out b, out maxLength); if (!IsEnabled(signatureAlgorithm)) { return(false); } if (doAsync) { key = await PublicKeyLocator.LocatePublicKeyAsync(q, d, s, cancellationToken).ConfigureAwait(false); } else { key = PublicKeyLocator.LocatePublicKey(q, d, s, cancellationToken); } if ((key is RsaKeyParameters rsa) && rsa.Modulus.BitLength < MinimumRsaKeyLength) { return(false); } options = options.Clone(); options.NewLineFormat = NewLineFormat.Dos; // first check the body hash (if that's invalid, then the entire signature is invalid) var hash = Convert.ToBase64String(message.HashBody(options, signatureAlgorithm, bodyAlgorithm, maxLength)); if (hash != bh) { return(false); } using (var stream = new DkimSignatureStream(CreateVerifyContext(signatureAlgorithm, key))) { using (var filtered = new FilteredStream(stream)) { filtered.Add(options.CreateNewLineFilter()); WriteHeaders(options, message, headers, headerAlgorithm, filtered); // now include the DKIM-Signature header that we are verifying, // but only after removing the "b=" signature value. var header = GetSignedSignatureHeader(dkimSignature); switch (headerAlgorithm) { case DkimCanonicalizationAlgorithm.Relaxed: WriteHeaderRelaxed(options, filtered, header, true); break; default: WriteHeaderSimple(options, filtered, header, true); break; } filtered.Flush(); } return(stream.VerifySignature(b)); } }
void DkimSign(FormatOptions options, MimeMessage message, IList <string> headers) { var value = new StringBuilder("v=1"); var t = GetTimestamp(); byte[] signature, hash; Header dkim; options = options.Clone(); options.NewLineFormat = NewLineFormat.Dos; options.EnsureNewLine = true; switch (SignatureAlgorithm) { case DkimSignatureAlgorithm.Ed25519Sha256: value.Append("; a=ed25519-sha256"); break; case DkimSignatureAlgorithm.RsaSha256: value.Append("; a=rsa-sha256"); break; default: value.Append("; a=rsa-sha1"); break; } value.AppendFormat("; d={0}; s={1}", Domain, Selector); value.AppendFormat("; c={0}/{1}", HeaderCanonicalizationAlgorithm.ToString().ToLowerInvariant(), BodyCanonicalizationAlgorithm.ToString().ToLowerInvariant()); if (!string.IsNullOrEmpty(QueryMethod)) { value.AppendFormat("; q={0}", QueryMethod); } if (!string.IsNullOrEmpty(AgentOrUserIdentifier)) { value.AppendFormat("; i={0}", AgentOrUserIdentifier); } value.AppendFormat("; t={0}", t); using (var stream = new DkimSignatureStream(CreateSigningContext())) { using (var filtered = new FilteredStream(stream)) { filtered.Add(options.CreateNewLineFilter()); // write the specified message headers DkimVerifierBase.WriteHeaders(options, message, headers, HeaderCanonicalizationAlgorithm, filtered); value.AppendFormat("; h={0}", string.Join(":", headers.ToArray())); hash = message.HashBody(options, SignatureAlgorithm, BodyCanonicalizationAlgorithm, -1); value.AppendFormat("; bh={0}", Convert.ToBase64String(hash)); value.Append("; b="); dkim = new Header(HeaderId.DkimSignature, value.ToString()); message.Headers.Insert(0, dkim); switch (HeaderCanonicalizationAlgorithm) { case DkimCanonicalizationAlgorithm.Relaxed: DkimVerifierBase.WriteHeaderRelaxed(options, filtered, dkim, true); break; default: DkimVerifierBase.WriteHeaderSimple(options, filtered, dkim, true); break; } filtered.Flush(); } signature = stream.GenerateSignature(); dkim.Value += Convert.ToBase64String(signature); } }
async Task <bool> VerifyAsync(FormatOptions options, MimeMessage message, Header dkimSignature, bool doAsync, CancellationToken cancellationToken) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } if (dkimSignature == null) { throw new ArgumentNullException(nameof(dkimSignature)); } if (dkimSignature.Id != HeaderId.DkimSignature) { throw new ArgumentException("The signature parameter MUST be a DKIM-Signature header.", nameof(dkimSignature)); } var parameters = ParseParameterTags(dkimSignature.Id, dkimSignature.Value); DkimCanonicalizationAlgorithm headerAlgorithm, bodyAlgorithm; DkimSignatureAlgorithm signatureAlgorithm; AsymmetricKeyParameter key; string d, s, q, bh, b; string[] headers; int maxLength; ValidateDkimSignatureParameters(parameters, out signatureAlgorithm, out headerAlgorithm, out bodyAlgorithm, out d, out s, out q, out headers, out bh, out b, out maxLength); if (!IsEnabled(signatureAlgorithm)) { return(false); } options = options.Clone(); options.NewLineFormat = NewLineFormat.Dos; // first check the body hash (if that's invalid, then the entire signature is invalid) if (!VerifyBodyHash(options, message, signatureAlgorithm, bodyAlgorithm, maxLength, bh)) { return(false); } if (doAsync) { key = await PublicKeyLocator.LocatePublicKeyAsync(q, d, s, cancellationToken).ConfigureAwait(false); } else { key = PublicKeyLocator.LocatePublicKey(q, d, s, cancellationToken); } if ((key is RsaKeyParameters rsa) && rsa.Modulus.BitLength < MinimumRsaKeyLength) { return(false); } return(VerifySignature(options, message, dkimSignature, signatureAlgorithm, key, headers, headerAlgorithm, b)); }