- Jan 2023
-
justinsecurity.medium.com justinsecurity.medium.com
-
blog.joinmastodon.org blog.joinmastodon.org
-
We need to read the Signature header, split it into its parts (keyId, headers and signature), fetch the public key linked from keyId, create a comparison string from the plaintext headers we got in the same order as was given in the signature header, and then verify that string using the public key and the original signature.
```ruby require 'json' require 'http'
post '/inbox' do signature_header = request.headers['Signature'].split(',').map do |pair| pair.split('=').map do |value| value.gsub(/\A"/, '').gsub(/"\z/, '') # "foo" -> foo end end.to_h
key_id = signature_header['keyId'] headers = signature_header['headers'] signature = Base64.decode64(signature_header['signature'])
actor = JSON.parse(HTTP.get(key_id).to_s) key = OpenSSL::PKey::RSA.new(actor['publicKey']['publicKeyPem'])
comparison_string = headers.split(' ').map do |signed_header_name| if signed_header_name == '(request-target)' '(request-target): post /inbox' else "#{signed_header_name}: #{request.headers[signed_header_name.capitalize]}" end end
if key.verify(OpenSSL::Digest::SHA256.new, signature, comparison_string) request.body.rewind INBOX << request.body.read [200, 'OK'] else [401, 'Request signature could not be verified'] end end ```
-