Пример #1
0
        static void TestEmptyBody(DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm bodyAlgorithm, string expectedHash)
        {
            var signer   = CreateSigner(signatureAlgorithm, DkimCanonicalizationAlgorithm.Simple, bodyAlgorithm);
            var headers  = new [] { HeaderId.From, HeaderId.To, HeaderId.Subject, HeaderId.Date };
            var verifier = new DkimVerifier(new DummyPublicKeyLocator(DkimKeys.Public));
            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.Prepare(EncodingConstraint.SevenBit);

            signer.Sign(message, headers);

            VerifyDkimBodyHash(message, signatureAlgorithm, expectedHash);

            var dkim = message.Headers[0];

            if (signatureAlgorithm == DkimSignatureAlgorithm.RsaSha1)
            {
                Assert.IsFalse(verifier.Verify(message, dkim), "DKIM-Signature using rsa-sha1 should not verify.");

                // now enable rsa-sha1 to verify again, this time it should pass...
                verifier.Enable(DkimSignatureAlgorithm.RsaSha1);
            }

            Assert.IsTrue(verifier.Verify(message, dkim), "Failed to verify DKIM-Signature.");
        }
Пример #2
0
        public void TestFormatExceptions()
        {
            var message  = MimeMessage.Load(Path.Combine(TestHelper.ProjectDir, "TestData", "dkim", "gmail.msg"));
            var verifier = new DkimVerifier(new DummyPublicKeyLocator(DkimKeys.Public));
            var index    = message.Headers.IndexOf(HeaderId.DkimSignature);
            var dkim     = message.Headers[index];
            var original = dkim.Value;

            // first, remove the 'v' tag and its value
            dkim.Value = dkim.Value.Substring(4);

            Assert.Throws <FormatException> (() => verifier.Verify(message, dkim), "Expected FormatException for missing v=1;");

            // add back a 'v' tag with an invalid value
            dkim.Value = "v=x; " + dkim.Value;

            Assert.Throws <FormatException> (() => verifier.Verify(message, dkim), "Expected FormatException for v=x;");

            // remove "from:"
            dkim.Value = original.Replace("from:", "");

            Assert.Throws <FormatException> (() => verifier.Verify(message, dkim), "Expected FormatException for missing from header");

            // add an invalid i= value w/o an '@'
            dkim.Value = "i=1; " + original;

            Assert.Throws <FormatException> (() => verifier.Verify(message, dkim), "Expected FormatException for an invalid i= value (missing '@')");

            // add an invalid i= value that does not match the domain
            dkim.Value = "i=user@domain; " + original;

            Assert.Throws <FormatException> (() => verifier.Verify(message, dkim), "Expected FormatException for an invalid i= that does not contain the domain");

            // add an invalid l= value
            dkim.Value = "l=abc; " + original;

            Assert.Throws <FormatException> (() => verifier.Verify(message, dkim), "Expected FormatException for an invalid l= value");

            // set an invalid body canonicalization algorithm
            dkim.Value = original.Replace("c=relaxed/relaxed;", "c=simple/complex;");

            Assert.Throws <FormatException> (() => verifier.Verify(message, dkim), "Expected FormatException for an invalid body canonicalization value");

            // set an invalid c= value
            dkim.Value = original.Replace("c=relaxed/relaxed;", "c=;");

            Assert.Throws <FormatException> (() => verifier.Verify(message, dkim), "Expected FormatException for an invalid c= value (empty)");

            // set an invalid c= value
            dkim.Value = original.Replace("c=relaxed/relaxed;", "c=relaxed/relaxed/extra;");

            Assert.Throws <FormatException> (() => verifier.Verify(message, dkim), "Expected FormatException for an invalid c= value (3 values)");
        }
Пример #3
0
        public static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Help();
                return;
            }

            for (int i = 0; i < args.Length; i++)
            {
                if (args[i] == "--help")
                {
                    Help();
                    return;
                }
            }

            var locator  = new DkimPublicKeyLocator();
            var verifier = new DkimVerifier(locator);

            // RSA-SHA1 is disabled by default starting with MimeKit 2.2.0
            verifier.Enable(DkimSignatureAlgorithm.RsaSha1);

            for (int i = 0; i < args.Length; i++)
            {
                if (!File.Exists(args[i]))
                {
                    Console.Error.WriteLine("{0}: No such file.", args[i]);
                    continue;
                }

                Console.Write("{0} -> ", args[i]);

                var message = MimeMessage.Load(args[i]);
                var index   = message.Headers.IndexOf(HeaderId.DkimSignature);

                if (index == -1)
                {
                    Console.WriteLine("NO SIGNATURE");
                    continue;
                }

                var dkim = message.Headers[index];

                if (verifier.Verify(message, dkim))
                {
                    // the DKIM-Signature header is valid!
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine("VALID");
                    Console.ResetColor();
                }
                else
                {
                    // the DKIM-Signature is invalid!
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("INVALID");
                    Console.ResetColor();
                }
            }
        }
Пример #4
0
        public void TestVerifyRfc8463Example()
        {
            var message  = MimeMessage.Load(Path.Combine(TestHelper.ProjectDir, "TestData", "dkim", "rfc8463-example.msg"));
            var locator  = new DkimPublicKeyLocator();
            var verifier = new DkimVerifier(locator);
            int index;

            locator.Add("brisbane._domainkey.football.example.com", "v=DKIM1; k=ed25519; p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=");
            locator.Add("test._domainkey.football.example.com", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB");

            // the last DKIM-Signature uses rsa-sha256
            index = message.Headers.LastIndexOf(HeaderId.DkimSignature);
            Assert.IsTrue(verifier.Verify(message, message.Headers[index]), "Failed to verify rsa-sha256");

            // the first DKIM-Signature uses ed25519-sha256
            index = message.Headers.IndexOf(HeaderId.DkimSignature);
            Assert.IsTrue(verifier.Verify(message, message.Headers[index]), "Failed to verify ed25519-sha256");
        }
Пример #5
0
        public void TestVerifyGoogleMultipartWithoutEndBoundaryDkimSignature()
        {
            var message  = MimeMessage.Load(Path.Combine(TestHelper.ProjectDir, "TestData", "dkim", "multipart-no-end-boundary.msg"));
            int index    = message.Headers.IndexOf(HeaderId.DkimSignature);
            var locator  = new DummyPublicKeyLocator(GMailDkimPublicKey);
            var verifier = new DkimVerifier(locator);

            Assert.IsTrue(verifier.Verify(message, message.Headers[index]), "Failed to verify GMail signature.");
        }
Пример #6
0
        public void TestVerifyGoogleMultipartRelatedDkimSignature()
        {
            var message  = MimeMessage.Load(Path.Combine("..", "..", "TestData", "dkim", "related.msg"));
            int index    = message.Headers.IndexOf(HeaderId.DkimSignature);
            var locator  = new DummyPublicKeyLocator(GMailDkimPublicKey);
            var verifier = new DkimVerifier(locator);

            Assert.IsTrue(verifier.Verify(message, message.Headers[index]), "Failed to verify GMail signature.");
        }
Пример #7
0
        static void TestDkimSignVerify(MimeMessage message, DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm headerAlgorithm, DkimCanonicalizationAlgorithm bodyAlgorithm)
        {
            var headers  = new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date };
            var verifier = new DkimVerifier(new DummyPublicKeyLocator(DkimKeys.Public));
            var signer   = CreateSigner(signatureAlgorithm, headerAlgorithm, bodyAlgorithm);

            signer.Sign(message, headers);

            var dkim = message.Headers[0];

            if (signatureAlgorithm == DkimSignatureAlgorithm.RsaSha1)
            {
                Assert.IsFalse(verifier.Verify(message, dkim), "DKIM-Signature using rsa-sha1 should not verify.");

                // now enable rsa-sha1 to verify again, this time it should pass...
                verifier.Enable(DkimSignatureAlgorithm.RsaSha1);
            }

            Assert.IsTrue(verifier.Verify(message, dkim), "Failed to verify DKIM-Signature.");

            message.Headers.RemoveAt(0);
        }
Пример #8
0
        static void TestUnicode(DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm bodyAlgorithm, string expectedHash)
        {
            var signer   = CreateSigner(signatureAlgorithm, DkimCanonicalizationAlgorithm.Simple, bodyAlgorithm);
            var headers  = new [] { HeaderId.From, HeaderId.To, HeaderId.Subject, HeaderId.Date };
            var verifier = new DkimVerifier(new DummyPublicKeyLocator(DkimKeys.Public));
            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.Prepare(EncodingConstraint.EightBit);

            signer.Sign(message, headers);

            var dkim = message.Headers[0];

            VerifyDkimBodyHash(message, signatureAlgorithm, expectedHash);

            if (signatureAlgorithm == DkimSignatureAlgorithm.RsaSha1)
            {
                Assert.IsFalse(verifier.Verify(message, dkim), "DKIM-Signature using rsa-sha1 should not verify.");

                // now enable rsa-sha1 to verify again, this time it should pass...
                verifier.Enable(DkimSignatureAlgorithm.RsaSha1);
            }

            Assert.IsTrue(verifier.Verify(message, dkim), "Failed to verify DKIM-Signature.");
        }
Пример #9
0
        public void TestSignRfc8463Example()
        {
            var message = MimeMessage.Load(Path.Combine(TestHelper.ProjectDir, "TestData", "dkim", "rfc8463-example.msg"));
            var signer  = new DkimSigner(Ed25519PrivateKey, "football.example.com", "brisbane", DkimSignatureAlgorithm.Ed25519Sha256)
            {
                HeaderCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Relaxed,
                BodyCanonicalizationAlgorithm   = DkimCanonicalizationAlgorithm.Relaxed,
                AgentOrUserIdentifier           = "@football.example.com"
            };
            var headers = new string[] { "from", "to", "subject", "date", "message-id", "from", "subject", "date" };

            signer.Sign(message, headers);

            int index    = message.Headers.IndexOf(HeaderId.DkimSignature);
            var locator  = new DkimPublicKeyLocator();
            var verifier = new DkimVerifier(locator);
            var dkim     = message.Headers[index];

            locator.Add("brisbane._domainkey.football.example.com", "v=DKIM1; k=ed25519; p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=");
            locator.Add("test._domainkey.football.example.com", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB");

            Assert.IsTrue(verifier.Verify(message, message.Headers[index]), "Failed to verify ed25519-sha256");
        }
Пример #10
0
        public void TestArgumentExceptions()
        {
            var        locator    = new DummyPublicKeyLocator(DkimKeys.Public);
            var        verifier   = new DkimVerifier(locator);
            var        dkimHeader = new Header(HeaderId.DkimSignature, "value");
            var        arcHeader  = new Header(HeaderId.ArcMessageSignature, "value");
            var        options    = FormatOptions.Default;
            var        message    = new MimeMessage();
            DkimSigner signer;

            Assert.Throws <ArgumentNullException> (() => new DkimSigner((AsymmetricKeyParameter)null, "domain", "selector"));
            Assert.Throws <ArgumentException> (() => new DkimSigner(DkimKeys.Public, "domain", "selector"));
            Assert.Throws <ArgumentNullException> (() => new DkimSigner(DkimKeys.Private, null, "selector"));
            Assert.Throws <ArgumentNullException> (() => new DkimSigner(DkimKeys.Private, "domain", null));
            Assert.Throws <ArgumentNullException> (() => new DkimSigner((string)null, "domain", "selector"));
            Assert.Throws <ArgumentNullException> (() => new DkimSigner("fileName", null, "selector"));
            Assert.Throws <ArgumentNullException> (() => new DkimSigner("fileName", "domain", null));
            Assert.Throws <ArgumentException> (() => new DkimSigner(string.Empty, "domain", "selector"));
            Assert.Throws <ArgumentNullException> (() => new DkimSigner((Stream)null, "domain", "selector"));
            using (var stream = File.OpenRead(Path.Combine(TestHelper.ProjectDir, "TestData", "dkim", "example.pem"))) {
                Assert.Throws <ArgumentNullException> (() => new DkimSigner(stream, null, "selector"));
                Assert.Throws <ArgumentNullException> (() => new DkimSigner(stream, "domain", null));

                signer = new DkimSigner(stream, "example.com", "1433868189.example")
                {
                    SignatureAlgorithm    = DkimSignatureAlgorithm.RsaSha1,
                    AgentOrUserIdentifier = "@eng.example.com",
                    QueryMethod           = "dns/txt",
                };
            }

            Assert.Throws <ArgumentNullException> (() => signer.Sign(null, new HeaderId[] { HeaderId.From }));
            Assert.Throws <ArgumentNullException> (() => signer.Sign(message, (IList <HeaderId>)null));
            Assert.Throws <ArgumentException> (() => signer.Sign(message, new HeaderId[] { HeaderId.Unknown, HeaderId.From }));
            Assert.Throws <ArgumentException> (() => signer.Sign(message, new HeaderId[] { HeaderId.Received, HeaderId.From }));
            Assert.Throws <ArgumentException> (() => signer.Sign(message, new HeaderId[] { HeaderId.ContentType }));
            Assert.Throws <ArgumentNullException> (() => signer.Sign(null, new string[] { "From" }));
            Assert.Throws <ArgumentNullException> (() => signer.Sign(message, (IList <string>)null));
            Assert.Throws <ArgumentException> (() => signer.Sign(message, new string[] { "", "From" }));
            Assert.Throws <ArgumentException> (() => signer.Sign(message, new string[] { null, "From" }));
            Assert.Throws <ArgumentException> (() => signer.Sign(message, new string[] { "Received", "From" }));
            Assert.Throws <ArgumentException> (() => signer.Sign(message, new string[] { "Content-Type" }));

            Assert.Throws <ArgumentNullException> (() => signer.Sign(null, message, new HeaderId[] { HeaderId.From }));
            Assert.Throws <ArgumentNullException> (() => signer.Sign(options, null, new HeaderId[] { HeaderId.From }));
            Assert.Throws <ArgumentException> (() => signer.Sign(options, message, new HeaderId[] { HeaderId.From, HeaderId.Unknown }));
            Assert.Throws <ArgumentNullException> (() => signer.Sign(options, message, (IList <HeaderId>)null));

            Assert.Throws <ArgumentNullException> (() => signer.Sign(null, message, new string[] { "From" }));
            Assert.Throws <ArgumentNullException> (() => signer.Sign(options, null, new string[] { "From" }));
            Assert.Throws <ArgumentException> (() => signer.Sign(options, message, new string[] { "From", null }));
            Assert.Throws <ArgumentNullException> (() => signer.Sign(options, message, (IList <string>)null));

            Assert.Throws <ArgumentNullException> (() => new DkimVerifier(null));

            Assert.Throws <ArgumentNullException> (() => verifier.Verify(null, dkimHeader));
            Assert.Throws <ArgumentNullException> (() => verifier.Verify(message, null));
            Assert.Throws <ArgumentNullException> (() => verifier.Verify(null, message, dkimHeader));
            Assert.Throws <ArgumentNullException> (() => verifier.Verify(FormatOptions.Default, null, dkimHeader));
            Assert.Throws <ArgumentNullException> (() => verifier.Verify(FormatOptions.Default, message, null));
            Assert.Throws <ArgumentException> (() => verifier.Verify(FormatOptions.Default, message, arcHeader));

            Assert.ThrowsAsync <ArgumentNullException> (async() => await verifier.VerifyAsync(null, dkimHeader));
            Assert.ThrowsAsync <ArgumentNullException> (async() => await verifier.VerifyAsync(message, null));
            Assert.ThrowsAsync <ArgumentNullException> (async() => await verifier.VerifyAsync(null, message, dkimHeader));
            Assert.ThrowsAsync <ArgumentNullException> (async() => await verifier.VerifyAsync(FormatOptions.Default, null, dkimHeader));
            Assert.ThrowsAsync <ArgumentNullException> (async() => await verifier.VerifyAsync(FormatOptions.Default, message, null));
            Assert.ThrowsAsync <ArgumentException> (async() => await verifier.VerifyAsync(FormatOptions.Default, message, arcHeader));

            Assert.Throws <ArgumentNullException> (() => message.Sign(null, new HeaderId[] { HeaderId.From }));
            Assert.Throws <ArgumentNullException> (() => message.Sign(signer, (IList <HeaderId>)null));
            Assert.Throws <ArgumentException> (() => message.Sign(signer, new HeaderId[] { HeaderId.Unknown, HeaderId.From }));
            Assert.Throws <ArgumentException> (() => message.Sign(signer, new HeaderId[] { HeaderId.Received, HeaderId.From }));
            Assert.Throws <ArgumentException> (() => message.Sign(signer, new HeaderId[] { HeaderId.ContentType }));
            Assert.Throws <ArgumentNullException> (() => message.Sign(null, new string[] { "From" }));
            Assert.Throws <ArgumentNullException> (() => message.Sign(signer, (IList <string>)null));
            Assert.Throws <ArgumentException> (() => message.Sign(signer, new string[] { "", "From" }));
            Assert.Throws <ArgumentException> (() => message.Sign(signer, new string[] { null, "From" }));
            Assert.Throws <ArgumentException> (() => message.Sign(signer, new string[] { "Received", "From" }));
            Assert.Throws <ArgumentException> (() => message.Sign(signer, new string[] { "Content-Type" }));

            Assert.Throws <ArgumentNullException> (() => message.Sign(null, signer, new HeaderId[] { HeaderId.From }));
            Assert.Throws <ArgumentNullException> (() => message.Sign(options, null, new HeaderId[] { HeaderId.From }));
            Assert.Throws <ArgumentException> (() => message.Sign(options, signer, new HeaderId[] { HeaderId.From, HeaderId.Unknown }));
            Assert.Throws <ArgumentNullException> (() => message.Sign(options, signer, (IList <HeaderId>)null));

            Assert.Throws <ArgumentNullException> (() => message.Sign(null, signer, new string[] { "From" }));
            Assert.Throws <ArgumentNullException> (() => message.Sign(options, null, new string[] { "From" }));
            Assert.Throws <ArgumentException> (() => message.Sign(options, signer, new string[] { "From", null }));
            Assert.Throws <ArgumentNullException> (() => message.Sign(options, signer, (IList <string>)null));

            Assert.Throws <ArgumentNullException> (() => message.Verify(null, locator));
            Assert.Throws <ArgumentNullException> (() => message.Verify(dkimHeader, null));
            Assert.Throws <ArgumentNullException> (() => message.Verify(null, dkimHeader, locator));
            Assert.Throws <ArgumentNullException> (() => message.Verify(FormatOptions.Default, null, locator));
            Assert.Throws <ArgumentNullException> (() => message.Verify(FormatOptions.Default, dkimHeader, null));
            Assert.Throws <ArgumentException> (() => message.Verify(FormatOptions.Default, arcHeader, locator));

            Assert.ThrowsAsync <ArgumentNullException> (async() => await message.VerifyAsync(null, locator));
            Assert.ThrowsAsync <ArgumentNullException> (async() => await message.VerifyAsync(dkimHeader, null));
            Assert.ThrowsAsync <ArgumentNullException> (async() => await message.VerifyAsync(null, dkimHeader, locator));
            Assert.ThrowsAsync <ArgumentNullException> (async() => await message.VerifyAsync(FormatOptions.Default, null, locator));
            Assert.ThrowsAsync <ArgumentNullException> (async() => await message.VerifyAsync(FormatOptions.Default, dkimHeader, null));
            Assert.ThrowsAsync <ArgumentException> (async() => await message.VerifyAsync(FormatOptions.Default, arcHeader, locator));
        }