Quantcast
Channel: March 2024 – Terence Eden’s Blog
Viewing all articles
Browse latest Browse all 20

I made a mistake in verifying HTTP Message Signatures

$
0
0

It's never great to find out you're wrong, but that's how learning and personal growth happens.

HTTP Message Signatures are hard1. There are lots of complex parts and getting any aspect wrong means certain death2.

In a previous post, I wrote A simple(ish) guide to verifying HTTP Message Signatures in PHP. It turns out that it was too simple. And far too trusting.

An HTTP Message Signature is a header which is separate to the message it signs. You might receive a JSON message like this:

{
   "actor":   "https://example.com/user/Alice",
   "message": "We strike at dawn!"
}

How do you know that really came from Alice? You look at the header of the message. It will be something like:

Signature: 
   keyId="https://example.org/user/Alice#main-key",
   algorithm="rsa-sha256",
   headers="(request-target) host date digest",
   signature="/AJ4Dv/wSL3XE1dLjFHCYVc7AF4f3+Q10G/r8+6cPsooiUh2K3YX3z++Nclo4qKHYr61yu+T4OMqUry1T6ZHmZqmNkg1RpVg=="

We want to check that Alice signed this message with her private key. So we grab her public key given by the keyId.
From there, we do some fancy maths using RSA-SHA256 and conclude that, when you put together the (request-target) host date digest content-type and compare them to the public key, they can only have be signed by the private key. Hurrah!

Did you spot the mistake I made? It wasn't in the maths, or the complex ordering of the data, or the algorithm choice, or some weird Unicode problem.

I made an error in trust.

Take a look at the Signature again.

The keyId is from example.org. But the actor is from example.com.

This message is signed correctly. It is cryptographically valid. But it wasn't signed by the actor in the message!

In this case, the fix is simple. Get the public key from keyId. Then independently get the named actor's public key. If they match, all is well. If not, skulduggery is afoot.

I'm almost tempted to say that you should ignore the provided keyId entirely; the source of truth is the actor's key - and the best way to get that is directly from the actor's profile.

Please explain why I'm wrong in the comments.


  1. You might think the Entscheidungsproblem is hard, but that's just peanuts compared to etc. etc. 
  2. Or cake. 

Viewing all articles
Browse latest Browse all 20

Trending Articles