Пример #1
0
		static DkimSigner CreateSigner (DkimSignatureAlgorithm algorithm)
		{
			return new DkimSigner (DkimKeys.Private, "example.com", "1433868189.example") {
				SignatureAlgorithm = algorithm,
				AgentOrUserIdentifier = "@eng.example.com",
				QueryMethod = "dns/txt",
			};
		}
Пример #2
0
		static DkimSigner CreateSigner (DkimSignatureAlgorithm algorithm)
		{
			return new DkimSigner (Path.Combine ("..", "..", "TestData", "dkim", "example.pem"), "example.com", "1433868189.example") {
				SignatureAlgorithm = algorithm,
				AgentOrUserIdentifier = "@eng.example.com",
				QueryMethod = "dns/txt",
			};
		}
Пример #3
0
		/// <summary>
		/// Initializes a new instance of the <see cref="MimeKit.Cryptography.DkimHashStream"/> class.
		/// </summary>
		/// <remarks>
		/// Creates a new <see cref="DkimHashStream"/>.
		/// </remarks>
		/// <param name="algorithm">The signature algorithm.</param>
		/// <param name="maxLength">The max length of data to hash.</param>
		public DkimHashStream (DkimSignatureAlgorithm algorithm, int maxLength = -1)
		{
			switch (algorithm) {
			case DkimSignatureAlgorithm.RsaSha256:
				digest = new Sha256Digest ();
				break;
			default:
				digest = new Sha1Digest ();
				break;
			}

			max = maxLength;
		}
Пример #4
0
		static void VerifyDkimBodyHash (MimeMessage message, DkimSignatureAlgorithm algorithm, string expectedHash)
		{
			var value = message.Headers[HeaderId.DkimSignature];
			var parameters = value.Split (';');
			string hash = null;

			for (int i = 0; i < parameters.Length; i++) {
				var param = parameters[i].Trim ();

				if (param.StartsWith ("bh=", StringComparison.Ordinal)) {
					hash = param.Substring (3);
					break;
				}
			}

			Assert.AreEqual (expectedHash, hash, "The {0} hash does not match the expected value.", algorithm.ToString ().ToUpperInvariant ().Substring (3));
		}
Пример #5
0
        /// <summary>
        /// Verify the signature of the message headers.
        /// </summary>
        /// <remarks>
        /// Verifies the signature of the message headers.
        /// </remarks>
        /// <param name="options">The formatting options.</param>
        /// <param name="message">The signed MIME message.</param>
        /// <param name="dkimSignature">The DKIM-Signature or ARC-Message-Signature header.</param>
        /// <param name="signatureAlgorithm">The algorithm used to sign the message headers.</param>
        /// <param name="key">The public key used to verify the signature.</param>
        /// <param name="headers">The list of headers that were signed.</param>
        /// <param name="canonicalizationAlgorithm">The algorithm used to canonicalize the headers.</param>
        /// <param name="signature">The expected signature of the headers encoded in base64.</param>
        /// <returns><c>true</c> if the calculated signature matches <paramref name="signature"/>; otherwise, <c>false</c>.</returns>
        protected bool VerifySignature(FormatOptions options, MimeMessage message, Header dkimSignature, DkimSignatureAlgorithm signatureAlgorithm, AsymmetricKeyParameter key, string[] headers, DkimCanonicalizationAlgorithm canonicalizationAlgorithm, string signature)
        {
            using (var stream = new DkimSignatureStream(CreateVerifyContext(signatureAlgorithm, key))) {
                using (var filtered = new FilteredStream(stream)) {
                    filtered.Add(options.CreateNewLineFilter());

                    WriteHeaders(options, message, headers, canonicalizationAlgorithm, filtered);

                    // now include the DKIM-Signature header that we are verifying,
                    // but only after removing the "b=" signature value.
                    var header = GetSignedSignatureHeader(dkimSignature);

                    switch (canonicalizationAlgorithm)
                    {
                    case DkimCanonicalizationAlgorithm.Relaxed:
                        WriteHeaderRelaxed(options, filtered, header, true);
                        break;

                    default:
                        WriteHeaderSimple(options, filtered, header, true);
                        break;
                    }

                    filtered.Flush();
                }

                return(stream.VerifySignature(signature));
            }
        }
Пример #6
0
 public ExampleArcSigner(Stream stream, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base(stream, domain, selector, algorithm)
 {
 }
Пример #7
0
		byte[] DkimHashBody (FormatOptions options, DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm bodyCanonicalizationAlgorithm, int maxLength)
		{
			using (var stream = new DkimHashStream (signatureAlgorithm, maxLength)) {
				using (var filtered = new FilteredStream (stream)) {
					filtered.Add (options.CreateNewLineFilter ());

					if (bodyCanonicalizationAlgorithm == DkimCanonicalizationAlgorithm.Relaxed)
						filtered.Add (new DkimRelaxedBodyFilter ());
					else
						filtered.Add (new DkimSimpleBodyFilter ());

					if (Body != null) {
						try {
							Body.Headers.Suppress = true;
							Body.WriteTo (options, stream, CancellationToken.None);
						} finally {
							Body.Headers.Suppress = false;
						}
					}

					filtered.Flush ();
				}

				return stream.GenerateHash ();
			}
		}
Пример #8
0
		static void TestUnicode (DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm bodyAlgorithm, string expectedHash)
		{
			var headers = new [] { HeaderId.From, HeaderId.To, HeaderId.Subject, HeaderId.Date };
			var signer = CreateSigner (signatureAlgorithm);
			var message = new MimeMessage ();

			message.From.Add (new MailboxAddress ("", "*****@*****.**"));
			message.To.Add (new MailboxAddress ("", "*****@*****.**"));
			message.Subject = "This is a unicode message";
			message.Date = DateTimeOffset.Now;

			var builder = new BodyBuilder ();
			builder.TextBody = " تست  ";
			builder.HtmlBody = "  <div> تست </div> ";
			message.Body = builder.ToMessageBody ();

			((Multipart) message.Body).Boundary = "=-MultipartAlternativeBoundary";
			((Multipart) message.Body)[1].ContentId = null;

			message.Body.Prepare (EncodingConstraint.EightBit);

			message.Sign (signer, headers, DkimCanonicalizationAlgorithm.Simple, bodyAlgorithm);

			var dkim = message.Headers[0];

			Console.WriteLine ("{0}", dkim.Value);

			VerifyDkimBodyHash (message, signatureAlgorithm, expectedHash);

			Assert.IsTrue (message.Verify (dkim, new DummyPublicKeyLocator (DkimKeys.Public)), "Failed to verify DKIM-Signature.");
		}
Пример #9
0
		static void ValidateDkimSignatureParameters (IDictionary<string, string> parameters, out DkimSignatureAlgorithm algorithm, out DkimCanonicalizationAlgorithm headerAlgorithm,
			out DkimCanonicalizationAlgorithm bodyAlgorithm, out string d, out string s, out string q, out string[] headers, out string bh, out string b, out int maxLength)
		{
			bool containsFrom = false;
			string v, a, c, h, l, id;

			if (!parameters.TryGetValue ("v", out v))
				throw new FormatException ("Malformed DKIM-Signature header: no version parameter detected.");

			if (v != "1")
				throw new FormatException (string.Format ("Unrecognized DKIM-Signature version: v={0}", v));

			if (!parameters.TryGetValue ("a", out a))
				throw new FormatException ("Malformed DKIM-Signature header: no signature algorithm parameter detected.");

			switch (a.ToLowerInvariant ()) {
			case "rsa-sha256": algorithm = DkimSignatureAlgorithm.RsaSha256; break;
			case "rsa-sha1": algorithm = DkimSignatureAlgorithm.RsaSha1; break;
			default: throw new FormatException (string.Format ("Unrecognized DKIM-Signature algorithm parameter: a={0}", a));
			}

			if (!parameters.TryGetValue ("d", out d))
				throw new FormatException ("Malformed DKIM-Signature header: no domain parameter detected.");

			if (parameters.TryGetValue ("i", out id)) {
				string ident;
				int at;

				if ((at = id.LastIndexOf ('@')) == -1)
					throw new FormatException ("Malformed DKIM-Signature header: no @ in the AUID value.");

				ident = id.Substring (at + 1);

				if (!ident.Equals (d, StringComparison.OrdinalIgnoreCase) && !ident.EndsWith ("." + d, StringComparison.OrdinalIgnoreCase))
					throw new FormatException ("Invalid DKIM-Signature header: the domain in the AUID does not match the domain parameter.");
			}

			if (!parameters.TryGetValue ("s", out s))
				throw new FormatException ("Malformed DKIM-Signature header: no selector parameter detected.");

			if (!parameters.TryGetValue ("q", out q))
				q = "dns/txt";

			if (parameters.TryGetValue ("l", out l)) {
				if (!int.TryParse (l, out maxLength))
					throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid length parameter: l={0}", l));
			} else {
				maxLength = -1;
			}

			if (parameters.TryGetValue ("c", out c)) {
				var tokens = c.ToLowerInvariant ().Split ('/');

				if (tokens.Length == 0 || tokens.Length > 2)
					throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid canonicalization parameter: c={0}", c));

				switch (tokens[0]) {
				case "relaxed": headerAlgorithm = DkimCanonicalizationAlgorithm.Relaxed; break;
				case "simple": headerAlgorithm = DkimCanonicalizationAlgorithm.Simple; break;
				default: throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid canonicalization parameter: c={0}", c));
				}

				if (tokens.Length == 2) {
					switch (tokens[1]) {
					case "relaxed": bodyAlgorithm = DkimCanonicalizationAlgorithm.Relaxed; break;
					case "simple": bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple; break;
					default: throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid canonicalization parameter: c={0}", c));
					}
				} else {
					bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple;
				}
			} else {
				headerAlgorithm = DkimCanonicalizationAlgorithm.Simple;
				bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple;
			}

			if (!parameters.TryGetValue ("h", out h))
				throw new FormatException ("Malformed DKIM-Signature header: no signed header parameter detected.");

			headers = h.Split (':');
			for (int i = 0; i < headers.Length; i++) {
				if (headers[i].Equals ("from", StringComparison.OrdinalIgnoreCase)) {
					containsFrom = true;
					break;
				}
			}

			if (!containsFrom)
				throw new FormatException (string.Format ("Malformed DKIM-Signature header: From header not signed."));

			if (!parameters.TryGetValue ("bh", out bh))
				throw new FormatException ("Malformed DKIM-Signature header: no body hash parameter detected.");

			if (!parameters.TryGetValue ("b", out b))
				throw new FormatException ("Malformed DKIM-Signature header: no signature parameter detected.");
		}
Пример #10
0
 /// <summary>
 /// Initialize a new instance of the <see cref="ArcSigner"/> class.
 /// </summary>
 /// <remarks>
 /// Creates a new <see cref="ArcSigner"/>.
 /// </remarks>
 /// <param name="domain">The domain that the signer represents.</param>
 /// <param name="selector">The selector subdividing the domain.</param>
 /// <param name="algorithm">The signature algorithm.</param>
 /// <exception cref="System.ArgumentNullException">
 /// <para><paramref name="domain"/> is <c>null</c>.</para>
 /// <para>-or-</para>
 /// <para><paramref name="selector"/> is <c>null</c>.</para>
 /// </exception>
 protected ArcSigner(string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base(domain, selector, algorithm)
 {
 }
Пример #11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MimeKit.Cryptography.ArcSigner"/> class.
        /// </summary>
        /// <remarks>
        /// Creates a new <see cref="ArcSigner"/>.
        /// </remarks>
        /// <param name="key">The signer's private key.</param>
        /// <param name="domain">The domain that the signer represents.</param>
        /// <param name="selector">The selector subdividing the domain.</param>
        /// <param name="algorithm">The signature algorithm.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="key"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="domain"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="selector"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// <paramref name="key"/> is not a private key.
        /// </exception>
        protected ArcSigner(AsymmetricKeyParameter key, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : this(domain, selector, algorithm)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            if (!key.IsPrivate)
            {
                throw new ArgumentException("The key must be a private key.", nameof(key));
            }

            PrivateKey = key;
        }
Пример #12
0
        static void ValidateDkimSignatureParameters(IDictionary <string, string> parameters, out DkimSignatureAlgorithm algorithm, out DkimCanonicalizationAlgorithm headerAlgorithm,
                                                    out DkimCanonicalizationAlgorithm bodyAlgorithm, out string d, out string s, out string q, out string[] headers, out string bh, out string b, out int maxLength)
        {
            bool containsFrom = false;

            if (!parameters.TryGetValue("v", out string v))
            {
                throw new FormatException("Malformed DKIM-Signature header: no version parameter detected.");
            }

            if (v != "1")
            {
                throw new FormatException(string.Format("Unrecognized DKIM-Signature version: v={0}", v));
            }

            ValidateCommonSignatureParameters("DKIM-Signature", parameters, out algorithm, out headerAlgorithm, out bodyAlgorithm, out d, out s, out q, out headers, out bh, out b, out maxLength);

            for (int i = 0; i < headers.Length; i++)
            {
                if (headers[i].Equals("from", StringComparison.OrdinalIgnoreCase))
                {
                    containsFrom = true;
                    break;
                }
            }

            if (!containsFrom)
            {
                throw new FormatException("Malformed DKIM-Signature header: From header not signed.");
            }

            if (parameters.TryGetValue("i", out string id))
            {
                string ident;
                int    at;

                if ((at = id.LastIndexOf('@')) == -1)
                {
                    throw new FormatException("Malformed DKIM-Signature header: no @ in the AUID value.");
                }

                ident = id.Substring(at + 1);

                if (!ident.Equals(d, StringComparison.OrdinalIgnoreCase) && !ident.EndsWith("." + d, StringComparison.OrdinalIgnoreCase))
                {
                    throw new FormatException("Invalid DKIM-Signature header: the domain in the AUID does not match the domain parameter.");
                }
            }
        }
Пример #13
0
		byte[] DkimHashBody (FormatOptions options, DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm bodyCanonicalizationAlgorithm, int maxLength)
		{
			using (var stream = new DkimHashStream (signatureAlgorithm, maxLength)) {
				using (var filtered = new FilteredStream (stream)) {
					DkimBodyFilter dkim;

					if (bodyCanonicalizationAlgorithm == DkimCanonicalizationAlgorithm.Relaxed)
						dkim = new DkimRelaxedBodyFilter ();
					else
						dkim = new DkimSimpleBodyFilter ();

					filtered.Add (options.CreateNewLineFilter ());
					filtered.Add (dkim);

					if (Body != null) {
						try {
							Body.EnsureNewLine = compliance == RfcComplianceMode.Strict;
							Body.Headers.Suppress = true;
							Body.WriteTo (options, filtered, CancellationToken.None);
						} finally {
							Body.Headers.Suppress = false;
							Body.EnsureNewLine = false;
						}
					}

					filtered.Flush ();

					if (!dkim.LastWasNewLine)
						stream.Write (options.NewLineBytes, 0, options.NewLineBytes.Length);
				}

				return stream.GenerateHash ();
			}
		}
Пример #14
0
 public DummyArcSigner(AsymmetricKeyParameter key, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base(key, domain, selector, algorithm)
 {
 }
Пример #15
0
 public DummyArcSigner(string fileName, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base(fileName, domain, selector, algorithm)
 {
 }
Пример #16
0
 static void ValidateArcMessageSignatureParameters(IDictionary <string, string> parameters, out DkimSignatureAlgorithm algorithm, out DkimCanonicalizationAlgorithm headerAlgorithm,
                                                   out DkimCanonicalizationAlgorithm bodyAlgorithm, out string d, out string s, out string q, out string[] headers, out string bh, out string b, out int maxLength)
 {
     ValidateCommonSignatureParameters("ARC-Message-Signature", parameters, out algorithm, out headerAlgorithm, out bodyAlgorithm, out d, out s, out q, out headers, out bh, out b, out maxLength);
 }
Пример #17
0
        static void ValidateArcSealParameters(IDictionary <string, string> parameters, out DkimSignatureAlgorithm algorithm, out string d, out string s, out string q, out string b)
        {
            ValidateCommonParameters("ARC-Seal", parameters, out algorithm, out d, out s, out q, out b);

            if (parameters.TryGetValue("h", out string h))
            {
                throw new FormatException(string.Format("Malformed ARC-Seal header: the 'h' parameter tag is not allowed."));
            }
        }
Пример #18
0
 /// <summary>
 /// Enable a DKIM signature algorithm.
 /// </summary>
 /// <remarks>
 /// <para>Enables the specified DKIM signature algorithm.</para>
 /// <note type="security">Due to the recognized weakness of the SHA-1 hash algorithm
 /// and the wide availability of the SHA-256 hash algorithm (it has been a required
 /// part of DKIM since it was originally standardized in 2007), it is recommended
 /// that <see cref="DkimSignatureAlgorithm.RsaSha1"/> NOT be enabled.</note>
 /// </remarks>
 /// <param name="algorithm">The DKIM signature algorithm.</param>
 public void Enable(DkimSignatureAlgorithm algorithm)
 {
     enabledSignatureAlgorithms |= 1 << (int)algorithm;
 }
Пример #19
0
 /// <summary>
 /// Disable a DKIM signature algorithm.
 /// </summary>
 /// <remarks>
 /// <para>Disables the specified DKIM signature algorithm.</para>
 /// <note type="security">Due to the recognized weakness of the SHA-1 hash algorithm
 /// and the wide availability of the SHA-256 hash algorithm (it has been a required
 /// part of DKIM since it was originally standardized in 2007), it is recommended
 /// that <see cref="DkimSignatureAlgorithm.RsaSha1"/> NOT be enabled.</note>
 /// </remarks>
 /// <param name="algorithm">The DKIM signature algorithm.</param>
 public void Disable(DkimSignatureAlgorithm algorithm)
 {
     enabledSignatureAlgorithms &= ~(1 << (int)algorithm);
 }
Пример #20
0
 /// <summary>
 /// Check whether a DKIM signature algorithm is enabled.
 /// </summary>
 /// <remarks>
 /// <para>Determines whether the specified DKIM signature algorithm is enabled.</para>
 /// <note type="security">Due to the recognized weakness of the SHA-1 hash algorithm
 /// and the wide availability of the SHA-256 hash algorithm (it has been a required
 /// part of DKIM since it was originally standardized in 2007), it is recommended
 /// that <see cref="DkimSignatureAlgorithm.RsaSha1"/> NOT be enabled.</note>
 /// </remarks>
 /// <returns><c>true</c> if the specified DKIM signature algorithm is enabled; otherwise, <c>false</c>.</returns>
 /// <param name="algorithm">The DKIM signature algorithm.</param>
 public bool IsEnabled(DkimSignatureAlgorithm algorithm)
 {
     return((enabledSignatureAlgorithms & (1 << (int)algorithm)) != 0);
 }
Пример #21
0
		static void TestEmptyBody (DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm bodyAlgorithm, string expectedHash)
		{
			var headers = new [] { HeaderId.From, HeaderId.To, HeaderId.Subject, HeaderId.Date };
			var signer = CreateSigner (signatureAlgorithm);
			var message = new MimeMessage ();

			message.From.Add (new MailboxAddress ("", "*****@*****.**"));
			message.To.Add (new MailboxAddress ("", "*****@*****.**"));
			message.Subject = "This is an empty message";
			message.Date = DateTimeOffset.Now;

			message.Body = new TextPart ("plain") { Text = "" };

			message.Body.Prepare (EncodingConstraint.SevenBit);

			message.Sign (signer, headers, DkimCanonicalizationAlgorithm.Simple, bodyAlgorithm);

			VerifyDkimBodyHash (message, signatureAlgorithm, expectedHash);

			var dkim = message.Headers[0];

			Assert.IsTrue (message.Verify (dkim, new DummyPublicKeyLocator (DkimKeys.Public)), "Failed to verify DKIM-Signature.");
		}
Пример #22
0
        internal static void ValidateCommonParameters(string header, IDictionary <string, string> parameters, out DkimSignatureAlgorithm algorithm,
                                                      out string d, out string s, out string q, out string b)
        {
            if (!parameters.TryGetValue("a", out string a))
            {
                throw new FormatException(string.Format("Malformed {0} header: no signature algorithm parameter detected.", header));
            }

            switch (a.ToLowerInvariant())
            {
            case "ed25519-sha256": algorithm = DkimSignatureAlgorithm.Ed25519Sha256; break;

            case "rsa-sha256": algorithm = DkimSignatureAlgorithm.RsaSha256; break;

            case "rsa-sha1": algorithm = DkimSignatureAlgorithm.RsaSha1; break;

            default: throw new FormatException(string.Format("Unrecognized {0} algorithm parameter: a={1}", header, a));
            }

            if (!parameters.TryGetValue("d", out d))
            {
                throw new FormatException(string.Format("Malformed {0} header: no domain parameter detected.", header));
            }

            if (d.Length == 0)
            {
                throw new FormatException(string.Format("Malformed {0} header: empty domain parameter detected.", header));
            }

            if (!parameters.TryGetValue("s", out s))
            {
                throw new FormatException(string.Format("Malformed {0} header: no selector parameter detected.", header));
            }

            if (s.Length == 0)
            {
                throw new FormatException(string.Format("Malformed {0} header: empty selector parameter detected.", header));
            }

            if (!parameters.TryGetValue("q", out q))
            {
                q = "dns/txt";
            }

            if (!parameters.TryGetValue("b", out b))
            {
                throw new FormatException(string.Format("Malformed {0} header: no signature parameter detected.", header));
            }

            if (b.Length == 0)
            {
                throw new FormatException(string.Format("Malformed {0} header: empty signature parameter detected.", header));
            }

            if (parameters.TryGetValue("t", out string t))
            {
                if (!int.TryParse(t, NumberStyles.Integer, CultureInfo.InvariantCulture, out int timestamp) || timestamp < 0)
                {
                    throw new FormatException(string.Format("Malformed {0} header: invalid timestamp parameter: t={1}.", header, t));
                }
            }
        }
Пример #23
0
		static void TestDkimSignVerify (MimeMessage message, DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm headerAlgorithm, DkimCanonicalizationAlgorithm bodyAlgorithm)
		{
			var headers = new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date };
			var signer = CreateSigner (signatureAlgorithm);

			message.Sign (signer, headers, headerAlgorithm, bodyAlgorithm);

			var dkim = message.Headers[0];

			Assert.IsTrue (message.Verify (dkim, new DummyPublicKeyLocator (DkimKeys.Public)), "Failed to verify DKIM-Signature.");

			message.Headers.RemoveAt (0);
		}
Пример #24
0
        internal static void ValidateCommonSignatureParameters(string header, IDictionary <string, string> parameters, out DkimSignatureAlgorithm algorithm, out DkimCanonicalizationAlgorithm headerAlgorithm,
                                                               out DkimCanonicalizationAlgorithm bodyAlgorithm, out string d, out string s, out string q, out string[] headers, out string bh, out string b, out int maxLength)
        {
            ValidateCommonParameters(header, parameters, out algorithm, out d, out s, out q, out b);

            if (parameters.TryGetValue("l", out string l))
            {
                if (!int.TryParse(l, NumberStyles.Integer, CultureInfo.InvariantCulture, out maxLength) || maxLength < 0)
                {
                    throw new FormatException(string.Format("Malformed {0} header: invalid length parameter: l={1}", header, l));
                }
            }
            else
            {
                maxLength = -1;
            }

            if (parameters.TryGetValue("c", out string c))
            {
                var tokens = c.ToLowerInvariant().Split('/');

                if (tokens.Length == 0 || tokens.Length > 2)
                {
                    throw new FormatException(string.Format("Malformed {0} header: invalid canonicalization parameter: c={1}", header, c));
                }

                switch (tokens[0])
                {
                case "relaxed": headerAlgorithm = DkimCanonicalizationAlgorithm.Relaxed; break;

                case "simple": headerAlgorithm = DkimCanonicalizationAlgorithm.Simple; break;

                default: throw new FormatException(string.Format("Malformed {0} header: invalid canonicalization parameter: c={1}", header, c));
                }

                if (tokens.Length == 2)
                {
                    switch (tokens[1])
                    {
                    case "relaxed": bodyAlgorithm = DkimCanonicalizationAlgorithm.Relaxed; break;

                    case "simple": bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple; break;

                    default: throw new FormatException(string.Format("Malformed {0} header: invalid canonicalization parameter: c={1}", header, c));
                    }
                }
                else
                {
                    bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple;
                }
            }
            else
            {
                headerAlgorithm = DkimCanonicalizationAlgorithm.Simple;
                bodyAlgorithm   = DkimCanonicalizationAlgorithm.Simple;
            }

            if (!parameters.TryGetValue("h", out string h))
            {
                throw new FormatException(string.Format("Malformed {0} header: no signed header parameter detected.", header));
            }

            headers = h.Split(':');

            if (!parameters.TryGetValue("bh", out bh))
            {
                throw new FormatException(string.Format("Malformed {0} header: no body hash parameter detected.", header));
            }
        }
Пример #25
0
		static ISigner DkimGetDigestSigner (DkimSignatureAlgorithm algorithm, AsymmetricKeyParameter key)
		{
			DerObjectIdentifier id;

			if (algorithm == DkimSignatureAlgorithm.RsaSha256)
				id = PkcsObjectIdentifiers.Sha256WithRsaEncryption;
			else
				id = PkcsObjectIdentifiers.Sha1WithRsaEncryption;

			var signer = SignerUtilities.GetSigner (id);

			signer.Init (key.IsPrivate, key);

			return signer;
		}
Пример #26
0
        /// <summary>
        /// Verify the hash of the message body.
        /// </summary>
        /// <remarks>
        /// Verifies the hash of the message body.
        /// </remarks>
        /// <param name="options">The formatting options.</param>
        /// <param name="message">The signed MIME message.</param>
        /// <param name="signatureAlgorithm">The algorithm used to sign the message.</param>
        /// <param name="canonicalizationAlgorithm">The algorithm used to canonicalize the message body.</param>
        /// <param name="maxLength">The max length of the message body to hash or <c>-1</c> to hash the entire message body.</param>
        /// <param name="bodyHash">The expected message body hash encoded in base64.</param>
        /// <returns><c>true</c> if the calculated body hash matches <paramref name="bodyHash"/>; otherwise, <c>false</c>.</returns>
        protected bool VerifyBodyHash(FormatOptions options, MimeMessage message, DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm canonicalizationAlgorithm, int maxLength, string bodyHash)
        {
            var hash = Convert.ToBase64String(message.HashBody(options, signatureAlgorithm, canonicalizationAlgorithm, maxLength));

            return(hash == bodyHash);
        }
Пример #27
0
		static void ValidateDkimSignatureParameters (IDictionary<string, string> parameters, out DkimSignatureAlgorithm algorithm, out DkimCanonicalizationAlgorithm headerAlgorithm,
			out DkimCanonicalizationAlgorithm bodyAlgorithm, out string d, out string s, out string q, out string h, out string bh, out string b, out int maxLength)
		{
			string v, a, c, l;

			if (!parameters.TryGetValue ("v", out v))
				throw new FormatException ("Malformed DKIM-Signature header: no version parameter detected.");

			if (v != "1")
				throw new FormatException (string.Format ("Unrecognized DKIM-Signature version: v={0}", v));

			if (!parameters.TryGetValue ("a", out a))
				throw new FormatException ("Malformed DKIM-Signature header: no signature algorithm parameter detected.");

			switch (a.ToLowerInvariant ()) {
			case "rsa-sha256": algorithm = DkimSignatureAlgorithm.RsaSha256; break;
			case "rsa-sha1": algorithm = DkimSignatureAlgorithm.RsaSha1; break;
			default: throw new FormatException (string.Format ("Unrecognized DKIM-Signature algorithm parameter: a={0}", a));
			}

			if (!parameters.TryGetValue ("d", out d))
				throw new FormatException ("Malformed DKIM-Signature header: no domain parameter detected.");

			if (!parameters.TryGetValue ("s", out s))
				throw new FormatException ("Malformed DKIM-Signature header: no selector parameter detected.");

			if (!parameters.TryGetValue ("q", out q))
				q = "dns/txt";

			if (parameters.TryGetValue ("l", out l)) {
				if (!int.TryParse (l, out maxLength))
					throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid length parameter: l={0}", l));
			} else {
				maxLength = -1;
			}

			if (parameters.TryGetValue ("c", out c)) {
				var tokens = c.ToLowerInvariant ().Split ('/');

				if (tokens.Length == 0 || tokens.Length > 2)
					throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid canonicalization parameter: c={0}", c));

				switch (tokens[0]) {
				case "relaxed": headerAlgorithm = DkimCanonicalizationAlgorithm.Relaxed; break;
				case "simple": headerAlgorithm = DkimCanonicalizationAlgorithm.Simple; break;
				default: throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid canonicalization parameter: c={0}", c));
				}

				if (tokens.Length == 2) {
					switch (tokens[1]) {
					case "relaxed": bodyAlgorithm = DkimCanonicalizationAlgorithm.Relaxed; break;
					case "simple": bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple; break;
					default: throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid canonicalization parameter: c={0}", c));
					}
				} else {
					bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple;
				}
			} else {
				headerAlgorithm = DkimCanonicalizationAlgorithm.Simple;
				bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple;
			}

			if (!parameters.TryGetValue ("h", out h))
				throw new FormatException ("Malformed DKIM-Signature header: no signed header parameter detected.");

			if (!parameters.TryGetValue ("bh", out bh))
				throw new FormatException ("Malformed DKIM-Signature header: no body hash parameter detected.");

			if (!parameters.TryGetValue ("b", out b))
				throw new FormatException ("Malformed DKIM-Signature header: no signature parameter detected.");
		}
Пример #28
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MimeKit.Cryptography.DkimSigner"/> class.
        /// </summary>
        /// <remarks>
        /// Creates a new <see cref="DkimSigner"/>.
        /// </remarks>
        /// <param name="key">The signer's private key.</param>
        /// <param name="domain">The domain that the signer represents.</param>
        /// <param name="selector">The selector subdividing the domain.</param>
        /// <param name="algorithm">The signature algorithm.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="key"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="domain"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="selector"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// <paramref name="key"/> is not a private key.
        /// </exception>
        public DkimSigner(AsymmetricKeyParameter key, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

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

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

            if (!key.IsPrivate)
            {
                throw new ArgumentException("The key must be a private key.", nameof(key));
            }

            SignatureAlgorithm = algorithm;
            Selector           = selector;
            PrivateKey         = key;
            Domain             = domain;
        }