« Home | Windows Azure - SlashView » | Windows Azure - Getting Started » | Silverlight 2: MVVM, Databinding & Cascading Combo... » | Silverlight 2: MVVM, Databinding & Cascading Combo... » | Google App Engine - Tetris Challenge » | IIS, SSL and Host-Headers » | Amazon EC2 - Now with Windows Server 2003! » | Playing with JQuery and ASP.NET MVC » | Converting Timezones in .net » | ASP.NET Defending Against Form Hackers » 

Sunday, August 30, 2009 

Verifying a DKIM signature in C#

Quick background: DomainKeys Identified Mail (DKIM) is a digital signature and hash which are placed on your emails to verify they are coming from the domain they claim to be. One step in the defence against SPAM and phishing emails.

What does the signature look like. Here's a signature grabbed from an email sent from Yahoo mail:

DKIM-Signature: 
 v=1; 
 a=rsa-sha256; 
 c=relaxed/relaxed; 
 d=yahoo.com.au; 
 s=s1024; 
 t=1250214285; 
 bh=cHSvmWBBhlnc7HYJ0cXdBZfzQDwcJskaGayavbFvzSY=; 
 h=Message-ID:X-YMail-OSG:Received:X-Mailer:Date:From:Subject:To:MIME-Version:Content-Type; 
 b=gsz2P/9h3SL8PwBIU8g9dMGnHI+mwfSqjDhrkJljG3HNCbL0I4/DZJBGHnuqRwgpP4Rq0K3E/1z2Zwez4OhMI+naVzGg0P0ePG75GOwfXvl0XBvN8x8j1pgIOS8KQS24E1+6RogWIKJR2mht+KwiFK5uq3BYc9+nC9XMWsIE1fw=

Verifying a signature is going to require a public key. The public key is grabbed from a TXT record on the sender's the domain. The domain name is built with the "s" and "d" tags above. "s" + "._domainkey." + d = "s1024._domainkey.yahoo.com.au".

Using nslookup from the command prompt give us:

C:\>nslookup
Default Server:  DD-WRT
Address:  192.168.1.1

> set type=TXT
> s1024._domainkey.yahoo.com.au
Server:  DD-WRT
Address:  192.168.1.1

Non-authoritative answer:
s1024._domainkey.yahoo.com.au   text =

        "k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4Pel
eB3gfm"
        "JiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB; n=A 1024 bit key
;"

The "b=" tag in DKIM-Signature is a signature of the canonicalized headers. The canonicalization process is done to make sure the signature is resilient to header modifications by mail servers. In this example we are using the 'relaxed' canonicalization algorithm. (Much more details about canonicalization in the RFC4871).

The original headers:

Message-ID: <88014.32082.qm@web112514.mail.gq1.yahoo.com>
X-YMail-OSG: aJFcCYUVM1mfioaf5zF7Pv_aQQ27DjD57ShG_QdRO6jTz5SGM4lVBkiJ1SD0tZmtvLEHhR4YtNFpTpI26b3VFERE44rlTAN3nP7a9.snzPvxcIIVOy6d0XWg1fvWS5bpOInMbv7M0bltJc6ml3gWPn8S3tT6U.Wz4OXu22meLo5VrikBRKeSGItA5Kw5Asn20GT84javGzv9_3znhG0HMejyHxpDjDbn.C_9OpKMVheG6HmBpgFVYmsW9q2IKc4r08YZvyADKNKnjN066fNhCNaYKWu3PEpHpbV4pZf66cFChegx94phIMQCI0cScc8ZQ5BLRj7qwV2F85C2ib22DWbZvTY-
Received: from [114.76.223.211] by web112514.mail.gq1.yahoo.com via HTTP; Thu, 13 Aug 2009 18:44:43 PDT
X-Mailer: YahooMailRC/1358.27 YahooMailWebService/0.7.338.2
Date: Thu, 13 Aug 2009 18:44:43 -0700 (PDT)
From: Russell Sayers 
Subject: from yahoo
To: diagnostic@smtp2web.com
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="0-1193717202-1250214283=:32082"
After relaxed canonicalization:
message-id:<88014.32082.qm@web112514.mail.gq1.yahoo.com>
x-ymail-osg:aJFcCYUVM1mfioaf5zF7Pv_aQQ27DjD57ShG_QdRO6jTz5SGM4lVBkiJ1SD0tZmtvLEHhR4YtNFpTpI26b3VFERE44rlTAN3nP7a9.snzPvxcIIVOy6d0XWg1fvWS5bpOInMbv7M0bltJc6ml3gWPn8S3tT6U.Wz4OXu22meLo5VrikBRKeSGItA5Kw5Asn20GT84javGzv9_3znhG0HMejyHxpDjDbn.C_9OpKMVheG6HmBpgFVYmsW9q2IKc4r08YZvyADKNKnjN066fNhCNaYKWu3PEpHpbV4pZf66cFChegx94phIMQCI0cScc8ZQ5BLRj7qwV2F85C2ib22DWbZvTY-
received:from [114.76.223.211] by web112514.mail.gq1.yahoo.com via HTTP; Thu, 13 Aug 2009 18:44:43 PDT
x-mailer:YahooMailRC/1358.27 YahooMailWebService/0.7.338.2
date:Thu, 13 Aug 2009 18:44:43 -0700 (PDT)
from:Russell Sayers 
subject:from yahoo
to:diagnostic@smtp2web.com
mime-version:1.0
content-type:multipart/alternative; boundary="0-1193717202-1250214283=:32082"

Now the canonicalized signature, minus the "b=" value. is placed after the headers. This had me scratching my head for a bit until I read this from the RFC:

The header field MUST be presented to the hash algorithm after the body of the message rather than with the rest of the header fields and MUST be canonicalized as specified in the "c=" (canonicalization) tag. The DKIM-Signature header field MUST NOT be included in its own h= tag..

We now have everything we need to verify the signature on the email using Bouncy Castle Crypto APIs

string base64pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB";
RsaKeyParameters pubKey = PublicKeyFactory.CreateKey(Convert.FromBase64String(base64pubkey)) as RsaKeyParameters;
byte[] signature = Convert.FromBase64String("gsz2P/9h3SL8PwBIU8g9dMGnHI+mwfSqjDhrkJljG3HNCbL0I4/DZJBGHnuqRwgpP4Rq0K3E/1z2Zwez4OhMI+naVzGg0P0ePG75GOwfXvl0XBvN8x8j1pgIOS8KQS24E1+6RogWIKJR2mht+KwiFK5uq3BYc9+nC9XMWsIE1fw=");

string canonicalized =
@"message-id:<88014.32082.qm@web112514.mail.gq1.yahoo.com>
x-ymail-osg:aJFcCYUVM1mfioaf5zF7Pv_aQQ27DjD57ShG_QdRO6jTz5SGM4lVBkiJ1SD0tZmtvLEHhR4YtNFpTpI26b3VFERE44rlTAN3nP7a9.snzPvxcIIVOy6d0XWg1fvWS5bpOInMbv7M0bltJc6ml3gWPn8S3tT6U.Wz4OXu22meLo5VrikBRKeSGItA5Kw5Asn20GT84javGzv9_3znhG0HMejyHxpDjDbn.C_9OpKMVheG6HmBpgFVYmsW9q2IKc4r08YZvyADKNKnjN066fNhCNaYKWu3PEpHpbV4pZf66cFChegx94phIMQCI0cScc8ZQ5BLRj7qwV2F85C2ib22DWbZvTY-
received:from [114.76.223.211] by web112514.mail.gq1.yahoo.com via HTTP; Thu, 13 Aug 2009 18:44:43 PDT
x-mailer:YahooMailRC/1358.27 YahooMailWebService/0.7.338.2
date:Thu, 13 Aug 2009 18:44:43 -0700 (PDT)
from:Russell Sayers &lt;russell_sayers@yahoo.com.au&gt;
subject:from yahoo
to:diagnostic@smtp2web.com
mime-version:1.0
content-type:multipart/alternative; boundary=""0-1193717202-1250214283=:32082""
dkim-signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com.au; s=s1024; t=1250214285; bh=cHSvmWBBhlnc7HYJ0cXdBZfzQDwcJskaGayavbFvzSY=; h=Message-ID:X-YMail-OSG:Received:X-Mailer:Date:From:Subject:To:MIME-Version:Content-Type; b=";
byte[] message = Encoding.ASCII.GetBytes(canonicalized);


ISigner sig = SignerUtilities.GetSigner("SHA256WithRSAEncryption");
sig.Init(false, pubKey);
sig.BlockUpdate(message, 0, message.Length);
if (sig.VerifySignature(signature))
{
    Console.WriteLine("all good!");
}

Labels: ,

Do you have an example signing an .eml message generated with SmtpClient?

There's code in this article for adding custom headers: http://msdn.microsoft.com/en-us/vbasic/bb630227.aspx. So I think it can be done.. I'll have an attempt at it and post up and article if it works.

Great! Yes, is easy to add coustom headers, I am not sure wich part of the message and how to sign it, but it seems that following what you did could be similar.

FYI - I've added a new article with a working sample sending an email Sending a DKIM Signed Email from C#

Nice

Post a Comment