-
Notifications
You must be signed in to change notification settings - Fork 251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
notification/webhook: all webhooks are signed by a new set of signing keys #4225
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get some info (PR description is fine):
- how the signature is calculated
- what is covered by the signature
- what is the signing algorithm
- how would to verify it manually
I know this is currently using our in-app code; but since this is going to be an external API, we'll need to talk through that before introducing it.
If we change anything about in-app signatures, this will need to remain as-is; so let's flush it out a bit.
Also, as mentioned in a comment, I think we need to include the GraphQL API for at least the public key to start so we can validate before enabling this.
Alternatively, we could put it behind an experimental flag until it's 100%.
test/smoke/webhook_signing_test.go
Outdated
valid, _ := h.App().WebhookKeyring.Verify(alert.Body, signatureBytes) | ||
|
||
if !assert.True(t, valid, "webhook signature invalid") { | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding the GraphQL/API bit (but not the UI changes) to grab the public key might be worthwhile so that the smoke test can demonstrate getting the key and verifying.
It's also essential we do NOT use any in-app code to verify the signature -- if the in-app keyring ever changes, the test won't detect the compatibility break; we need to insulate the two. This test should use it's own validation code, which should match whatever we'd document users use.
This will also help us understand how we expect verification to work externally.
Our existing keyring works well for internal GoAlert stuff. Still, we also need to do a little bit of digging into libraries of other languages to ensure validation isn't going to be painful if we use that too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the best method of ensuring external use-cases would be to allow the keyring to execute SignASN1
and MAYBE VerifyASN1
operations rather than sending r
/s
along side the signature itself; most libraries support ASN1 verification:
- Java via BouncyCastle (unclear to me if it supports ECDSA with SHA512/224 digest as we currently use without some extra work)
- Python via Cryptography (allows for precomputed hashes)
- Golang via crypto/ecdsa (requires digest input)
- Rust through RustCrypto or OpenSSL bindings (requires digest input)
- Erlang/Elixir through
:crypto
(can accept digest input)
Co-authored-by: Nathaniel Caza <[email protected]>
enables future work to retrieve public keys for human usage
…tead of internal signing mechanism allows for greater compatibility with external libraries/languages and reduces cryptographic attack surface
I think if we want to flesh this out a bit we should move to ECDSA P256 with SHA512 hashing rather than 512/224; it looks to me like BouncyCastle (Java, C#) supports 512 more than 512/224 (and I'd imagine 512 alone is more common than 512/224 for support in other languages that can take digests). Another strong consideration would be moving to Ed25519 for this; it would remove a large amount of complexity here (ASN1 vs. manual r/s, selection of hashing algorithm, etc) but would add additional complexity to the codebase (we would likely need to implement another |
I think using a more established combo is a good idea. We use the 224 mostly just for size since we sign and verify our own tokens internally. Since implementation may change a bit based on this convo, let's continue in the issue so it's easier to find/reference later: #4224 (comment) |
make check
to catch common errors. Fixed any that came up.Description:
This PR:
X-Webhook-Signature
, converting the raw binary signature to base64Further cryptographic details:
X-Webhook-Signature
from Base64 to bytesr
/s
from the DER-encoded ASN.1 payloadWhich issue(s) this PR fixes:
Part of #4224
Out of Scope:
Screenshots:
Describe any introduced user-facing changes:
Users will notice a new
X-Webhook-Signature
header on any outgoing webhook.They will not be able to validate the webhook signature with just this PR as the public key will not have been exposed.
Describe any introduced API changes:
N/a
Additional Info: