10

Based on this question I decided to sign emails send from ASP.NET.MVC to decrease SPAM score of emails, but I have some bug somewhere.

Code:

    public void SendEmail(MailMessage mailMessage)
    {
        string domain = "kup-nemovitost.cz";

        var message = MimeMessage.CreateFromMailMessage(mailMessage);

        HeaderId[] headers = new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date };
        DkimCanonicalizationAlgorithm headerAlgorithm = DkimCanonicalizationAlgorithm.Relaxed;
        DkimCanonicalizationAlgorithm bodyAlgorithm = DkimCanonicalizationAlgorithm.Relaxed;

        string dkimPath = Path.Combine(ConfigHelper.GetDataPath(), "DKIM");
        string privateKey = Path.Combine(dkimPath, "kup-nemovitost.cz.private.rsa");

        DkimSigner signer = new DkimSigner(privateKey, domain, "mail")
        {
            SignatureAlgorithm = DkimSignatureAlgorithm.RsaSha1,
            AgentOrUserIdentifier = "@" + domain,
            QueryMethod = "dns/txt",
        };         

        message.Prepare(EncodingConstraint.SevenBit);
        message.Sign(signer, headers, headerAlgorithm, bodyAlgorithm);

        using (var client = new MailKit.Net.Smtp.SmtpClient())
        {
            client.Connect("localhost", 25, false);
            client.Send(message);
            client.Disconnect(true);
        }          
    }

I check the result on http://www.isnotspam.com, the output is following:

DKIM check details:
----------------------------------------------------------

Result: invalid
ID(s) verified: header.From=no-reply@kup-nemovitost.cz
Selector=mail
domain=kup-nemovitost.cz
DomainKeys DNS Record=mail._domainkey.kup-nemovitost.cz

My DNS record is:

@ IN TXT "v=dkim1; s=mail; p=migfma0gcsqgsib3dqebaquaa4gnadcbiqkbgqdnov2pxnjmghdpxw5wpypk1rf7 kxs+5ouvh6f0hraryncku6wbvq+xovbgxz1kuddcb/s9o8wquftxrlffniik3wbm qc+upm+ndloxcxwy0bb2iktbgnmndjiexm/z0npaviwzebr2k6vqdzbp+lmcuece bwasqgw2fki5ospb4qidaqab"

UPDATE:

I fix some issues in DNS record and I have found better online checker at dkimcore.org

I still face validation issue of my public key. I generated 1024 RSA using puttyGen (ppk) and convert it to RSA format. The original file from PuttyGen is:

---- BEGIN SSH2 PUBLIC KEY ----
Comment: "rsa-key-20170606"
AAAAB3NzaC1yc2EAAAABJQAAAIEAiyEwx+Idlf/Qp2fTYrQMwV3MuF9W7yaKDMHk
hzoH+MqWKtNDngQoJcmbyrkMeF0VLYo246ma3gPZh9cDL7i8ygOYKagbyUjgtZFz
y+et0tY/+G/IZNaHiQp0QuG/J71uZrl4Jlgkq+0s5bZxpRR45aRpcG1HQMIm6Ku7
lgmOt88=
---- END SSH2 PUBLIC KEY ----

So I just copy the content (except the commented lines) to DNS record and I got following output from checker:

p=  AAAAB3NzaC1yc2EAAAABJQAAAIEAiyEwx+Idlf/Qp2fTYrQMwV3MuF9W7yaKDMHkhzoH+MqWKtNDngQoJcmbyrkMeF0VLYo246ma3gPZh9cDL7i8ygOYKagbyUjgtZFzy+et0tY/+G/IZNaHiQp0QuG/J71uZrl4Jlgkq+0s5bZxpRR45aRpcG1HQMIm6Ku7lgmOt88=
This doesn't seem to be a valid RSA public key: RSA.xs:178: OpenSSL error: wrong tag at blib/lib/Crypt/OpenSSL/RSA.pm (autosplit into blib/lib/auto/Crypt/OpenSSL/RSA/new_public_key.al) line 91.
Tomas Kubes
  • 23,880
  • 18
  • 111
  • 148
  • 1
    Ok so you have a bug somewhere. What is the the desired behavior as apposed to what is actually happening? – Nkosi Jun 05 '17 at 13:48
  • The desired behavior is that http://www.isnotspam.com shall confirm that email is signed with DKIM with result pass. – Tomas Kubes Jun 05 '17 at 20:05
  • 1
    Services like SendGrid have a pretty generous free tier that take care of most of the burden of not having your email land in spam boxes. – Sam Rueby Jun 06 '17 at 01:27
  • Can you at least attach raw email (headers + body) on which that isnotspam fails? – Evk Jun 06 '17 at 05:32
  • Your code looks fine, but your public key is strange (for example - has spaces: `...+lmcuece bwa...` < note space). I'd suggest to verify once again that you put your public key in dns txt record correctly. – Evk Jun 06 '17 at 07:18
  • @Evk You were right. I fix spaces in public and make public key shorter (1024), because my hosting provider strips long DNS records. Another problem was the name of DNS record should be mail._domainkey.kup-nemovitost.cz isntaed of @. I will wait until DNS records update and I will try validators tommorow. – Tomas Kubes Jun 06 '17 at 21:29
  • 2
    You now have your key in SSH2 format, you need another format (PEM). It should start like `---BEGIN RSA PUBLIC KEY --- MII....`. If you don't know how to generate such key with your tools - show the command you use now and I can help with fixing it. – Evk Jun 07 '17 at 10:26
  • @Evk OK, so can I use gitbash in Windows to generate this key? – Tomas Kubes Jun 07 '17 at 11:49
  • I think you mean `ssh-keygen` which is indeed available in gitbash. It also generates public key in wrong (for this purpose) format, but it can convert it. You can generate key with `ssh-keygen -b 2048 -f output` (or use already existing key you already generated) and then convert it to PEM with `ssh-keygen -f output.pub -m 'PEM' -e > public.pem` where `output.pub` is path to your public key and `public.pem` is path where result key in PEM format will be created. Your private key is already in PEM by the way, so you can look at it to see what format you expect. – Evk Jun 07 '17 at 12:10
  • @Evk I am almost done. Another problem is that my hosting provider insert space into DNS public key during DNS propagation. I am waiting for support. I believe it will work after they fix it. – Tomas Kubes Jun 07 '17 at 19:12
  • Good to know! Though I believe such fix can take quite some time on their side. – Evk Jun 07 '17 at 19:15

1 Answers1

4

As we figured out in comments - your code is fine, but you have problems with public key. First, it has spaces in dns txt record, which it cannot have. Then, you have wrong format for a public key (SSH2). Tools that verify signature expect different format (regular PEM RSA), which should look like this:

--- BEGIN RSA PUBLIC KEY ---
MII ....
--- END RSA PUBLIC KEY ---

So, the same as your private key. You can convert SSH2 key to PEM with

ssh-keygen -f output.pub -m 'PEM' -e > public.pem

Where output.pub is public key in SSH2 format. With such key (and without spaces in DNS record) it should work fine, assuming you put that into right dns record - key_selector._domainkey.your.domain.

Evk
  • 98,527
  • 8
  • 141
  • 191