diff options
author | pdp8 <pdp8@pdp8.info> | 2023-06-26 20:49:38 +0200 |
---|---|---|
committer | pdp8 <pdp8@pdp8.info> | 2023-06-26 20:49:38 +0200 |
commit | dfaac96870ac6a86ebb0b5e5c9365e1e0ef6e5bc (patch) | |
tree | 07f04481328a85cfe3e3ea4b8bee1a6c654636d6 /server.rb | |
parent | 8453f524515941f3c0a65b5ca3b9354be76b4c33 (diff) |
digest verification, fetch/send_signed refactored
Diffstat (limited to 'server.rb')
-rw-r--r-- | server.rb | 57 |
1 files changed, 30 insertions, 27 deletions
@@ -79,36 +79,39 @@ helpers do # https://github.com/mastodon/mastodon/blob/main/app/controllers/concerns/signature_verification.rb def verify! - # TODO verify digest - begin - signature_params = {} - request.env["HTTP_SIGNATURE"].split(',').each do |pair| - k, v = pair.split('=') - signature_params[k] = v.gsub('"', '') - end - - key_id = signature_params['keyId'] - headers = signature_params['headers'] - signature = Base64.decode64(signature_params['signature']) - actor = fetch key_id - key = OpenSSL::PKey::RSA.new(actor['publicKey']['publicKeyPem']) + # verify digest + request.body.rewind # in case someone already read it + body = request.body.read + sha256 = OpenSSL::Digest::SHA256.new + digest = "SHA-256=" + sha256.base64digest(body) + halt 403 unless digest == request.env["HTTP_DIGEST"] + + signature_params = {} + request.env["HTTP_SIGNATURE"].split(',').each do |pair| + k, v = pair.split('=') + signature_params[k] = v.gsub('"', '') + end - comparison = headers.split(' ').map do |signed_params_name| - if signed_params_name == '(request-target)' - '(request-target): post /inbox' - elsif signed_params_name == 'content-type' - "#{signed_params_name}: #{request.env["CONTENT_TYPE"]}" - else - "#{signed_params_name}: #{request.env["HTTP_" + signed_params_name.upcase]}" - end - end.join("\n") + key_id = signature_params['keyId'] + headers = signature_params['headers'] + signature = Base64.decode64(signature_params['signature']) + + actor = fetch key_id + halt 403 unless actor + key = OpenSSL::PKey::RSA.new(actor['publicKey']['publicKeyPem']) + + comparison = headers.split(' ').map do |signed_params_name| + if signed_params_name == '(request-target)' + '(request-target): post /inbox' + elsif signed_params_name == 'content-type' + "#{signed_params_name}: #{request.env["CONTENT_TYPE"]}" + else + "#{signed_params_name}: #{request.env["HTTP_" + signed_params_name.upcase]}" + end + end.join("\n") - halt 400 unless key.verify(OpenSSL::Digest.new('SHA256'), signature, comparison) - rescue => e - p request.env["HTTP_SIGNATURE"], e - halt 400 - end + halt 403 unless key.verify(OpenSSL::Digest.new('SHA256'), signature, comparison) end def create object |