I must verify an HTTP signature to guarantee the origin and integrity of a webhook data: https://www.blockcypher.com/dev/bitcoin/#webhook-signing
This is their x509 PKIX encoded signing key's public key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEflgGqpIAC9k65JicOPBgXZUExen4rWLq05KwYmZHphTU/fmi3Oe/ckyxo2w3Ayo/SCO/rU2NB90jtCJfz9i1ow==
I am following this specification to construct the signing string: https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#section-2.3
Here is a POST request from said webhook:
POST /api/blockcypher HTTP/1.1
Host: (...removed...)
Accept-Encoding: gzip
Content-Length: 1551
Content-Type: application/json
Date: Thu, 16 Feb 2023 11:55:43 UTC
Digest: SHA-256=BYzO03UhXY2O4gzJd+8g367LSEtO3cAMJfOjL0F0HiE=
Signature: keyId="https://www.blockcypher.com/dev/bitcoin/#webhook-signing",algorithm="ecdsa-sha256",signature="ZJfhAFQP19xfnWZo9KD9hyzoyR8fZ5uEyh6Ltu3z/vWL7Jr+aezw8n9U9Yq41APWJG+vnhmS8KoGV48X34vMYQ==",headers="(request-target) digest date"
User-Agent: BlockCypher HTTP Invoker
X-Eventid: 2cb85bdf-6181-49e6-9d9a-5e419898ee33
X-Eventtype: unconfirmed-tx
X-Ratelimit-Remaining: 174
{
(...removed...)
}
I've successfully matched the provided Digest header with a constructed digest of my own using the request's (removed) content (I've removed the content to reduce visual bloat).
From what I can gather with the specification provided above, this would be the constructed signature string for this particular request:
(request-target): post /api/blockcypher\n
digest: SHA-256=BYzO03UhXY2O4gzJd+8g367LSEtO3cAMJfOjL0F0HiE=\n
date: Thu, 16 Feb 2023 11:55:43 UTC
The specification mentions the (created)
and (expired)
headers' values "MUST be a Unix timestamp integer value", but doesn't talk about the Date
header. I've tried both Thu, 16 Feb 2023 11:55:43 UTC and 1676548543 without success.
The specification is confusing to me in some aspects. For instance, the signature string where the (created)
field is included, does not end with a new line (\n
).
My question is, is my signature string well constructed? If not, what am I doing wrong?
To sum up:
PUBLIC KEY (x509 PKIX encoded, I don't know what that means)
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEflgGqpIAC9k65JicOPBgXZUExen4rWLq05KwYmZHphTU/fmi3Oe/ckyxo2w3Ayo/SCO/rU2NB90jtCJfz9i1ow==
SIGNATURE
ZJfhAFQP19xfnWZo9KD9hyzoyR8fZ5uEyh6Ltu3z/vWL7Jr+aezw8n9U9Yq41APWJG+vnhmS8KoGV48X34vMYQ==
MESSAGE (I think)
(request-target): post /api/blockcypher\ndigest: SHA-256=BYzO03UhXY2O4gzJd+8g367LSEtO3cAMJfOjL0F0HiE=\ndate: Thu, 16 Feb 2023 11:55:43 UTC
The verification fails. I'm guessing it's because the signature string is not properly constructed.