soren.qvist
soren.qvist

Reputation: 7416

Verifying Amazon SNS signatures in C#

I have an ASP.NET endpoint where I receive Amazon SNS messages. I want to verify the signatures I receive along with those messages and have followed the guide at http://docs.aws.amazon.com/sns/latest/dg/SendMessageToHttp.example.java.html trying to match the Java code in C#. Here's what I have so far (I'm only interested in validating notifications, not subscription confirmations):

private X509Certificate2 cert;        

// cert is from constructor...

private bool IsValidMessageSignature(AmazonMessage msg)
{
    // Verify the signature
    var rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;
    var msgBytes = GetMessageBytes(msg);
    var signedBytes = Convert.FromBase64String(msg.Signature);
    return rsa.VerifyData(msgBytes, CryptoConfig.MapNameToOID("SHA1"), signedBytes);
}

private byte[] GetMessageBytes(AmazonMessage msg)
{
    // Construct message string
    var sb = new StringBuilder();
    sb.AppendLine("Message");
    sb.AppendLine(msg.Message);
    sb.AppendLine("MessageId");
    sb.AppendLine(msg.MessageId);
    if (msg.Subject != null)
    {
        sb.AppendLine("Subject");
        sb.AppendLine(msg.Subject);
    }
    sb.AppendLine("Timestamp");
    sb.AppendLine(msg.Timestamp);
    sb.AppendLine("TopicArn");
    sb.AppendLine(msg.TopicArn);
    sb.AppendLine("Type");
    sb.AppendLine(msg.Type);

    return Encoding.UTF8.GetBytes(sb.ToString());
}

The rsa.VerifyData() step returns false. I have built the example in Java as well, and here it works fine with the same message I'm trying to validate, and the same certificate that I'm using for C#.

Here's where the two programs differ as far as I can see. The C# GetMessageBytes byte-array returns 637 bytes, while the Java equivalent getMessageBytesToSign returns 627 bytes. Unfortunately I cannot post the message contents here for security reasons. My Java setup uses the windows-1252 charset by default, but even if I change the C# encoding to that the byte-array is still 637 in size. I'm not that experienced with encodings and the differences between C# and Java so I don't know if it's of any importance though.

Any ideas as to how my C# should be changed?

Upvotes: 6

Views: 2069

Answers (3)

Timothy Gonzalez
Timothy Gonzalez

Reputation: 1908

Amazon.SimpleNotificationService.Util.Message.ParseMessage(SNS_MESSAGE).IsMessageSignatureValid()

Upvotes: 11

Miriam Zusin
Miriam Zusin

Reputation: 186

It worked for me this way:

var sb = new StringBuilder();

sb.Append("Message\n");
sb.Append(notificationWrapper.Message).Append("\n");
sb.Append("MessageId\n");
sb.Append(notificationWrapper.MessageId).Append("\n");

if (notificationWrapper.Subject != null)
{
    sb.Append("Subject\n");
    sb.Append(notificationWrapper.Subject).Append("\n");
}

sb.Append("Timestamp\n");
sb.Append(notificationWrapper.Timestamp).Append("\n");
sb.Append("TopicArn\n");
sb.Append(notificationWrapper.TopicArn).Append("\n");
sb.Append("Type\n");
sb.Append(notificationWrapper.Type).Append("\n");

return Encoding.UTF8.GetBytes(sb.ToString());

Upvotes: 0

ntoskrnl
ntoskrnl

Reputation: 5744

The Java code ends lines with \n. The C# version (StringBuilder.AppendLine()) uses \r\n.

Upvotes: 0

Related Questions