diff --git a/lib/diaspora_federation.rb b/lib/diaspora_federation.rb index fa909b4..5756e2c 100644 --- a/lib/diaspora_federation.rb +++ b/lib/diaspora_federation.rb @@ -7,7 +7,6 @@ require "diaspora_federation/validators" require "diaspora_federation/fetcher" -require "diaspora_federation/signing" require "diaspora_federation/entities" require "diaspora_federation/discovery" @@ -221,7 +220,7 @@ module DiasporaFederation end def configuration_error(message) - logger.fatal("diaspora federation configuration error: #{message}") + logger.fatal "diaspora federation configuration error: #{message}" raise ConfigurationError, message end end diff --git a/lib/diaspora_federation/entities/relayable.rb b/lib/diaspora_federation/entities/relayable.rb index ce4b9b2..aa1ce4d 100644 --- a/lib/diaspora_federation/entities/relayable.rb +++ b/lib/diaspora_federation/entities/relayable.rb @@ -2,9 +2,14 @@ module DiasporaFederation module Entities # this is a module that defines common properties for relayable entities # which include Like, Comment, Participation, Message, etc. Each relayable - # has a parent, identified by guid. Relayables also are signed and signing/verificating + # has a parent, identified by guid. Relayables also are signed and signing/verification # logic is embedded into Salmon XML processing code. module Relayable + include Logging + + # digest instance used for signing + DIGEST = OpenSSL::Digest::SHA256.new + # on inclusion of this module the required properties for a relayable are added to the object that includes it # # @!attribute [r] parent_guid @@ -43,15 +48,12 @@ module DiasporaFederation super.tap do |hash| if author_signature.nil? privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key_by_diaspora_id, diaspora_id) - hash[:author_signature] = Signing.sign_with_key(hash, privkey) unless privkey.nil? + raise AuthorPrivateKeyNotFound, "author=#{diaspora_id} guid=#{guid}" if privkey.nil? + hash[:author_signature] = sign_with_key(privkey, hash) + logger.info "event=sign_with_key signature=author_signature author=#{diaspora_id} guid=#{guid}" end - if parent_author_signature.nil? - privkey = DiasporaFederation.callbacks.trigger( - :fetch_author_private_key_by_entity_guid, parent_type, parent_guid - ) - hash[:parent_author_signature] = Signing.sign_with_key(hash, privkey) unless privkey.nil? - end + try_sign_with_parent_author(hash) if parent_author_signature.nil? end end @@ -66,33 +68,84 @@ module DiasporaFederation end end - # Exception raised when verify_signatures fails to verify signatures (signatures are wrong) - class SignatureVerificationFailed < ArgumentError - end - # verifies the signatures (+author_signature+ and +parent_author_signature+ if needed) # @raise [SignatureVerificationFailed] if the signature is not valid or no public key is found def verify_signatures pubkey = DiasporaFederation.callbacks.trigger(:fetch_public_key_by_diaspora_id, diaspora_id) - raise SignatureVerificationFailed, "failed to fetch public key for #{diaspora_id}" if pubkey.nil? - raise SignatureVerificationFailed, "wrong author_signature" unless Signing.verify_signature( - data, author_signature, pubkey - ) + raise PublicKeyNotFound, "author_signature author=#{diaspora_id} guid=#{guid}" if pubkey.nil? + raise SignatureVerificationFailed, "wrong author_signature" unless verify_signature(pubkey, author_signature) - author_is_local = DiasporaFederation.callbacks.trigger(:entity_author_is_local?, parent_type, parent_guid) - verify_parent_signature unless author_is_local + parent_author_local = DiasporaFederation.callbacks.trigger(:entity_author_is_local?, parent_type, parent_guid) + verify_parent_author_signature unless parent_author_local end private + # sign with parent author, if the parent author is local (if the private key is found) + # @param [Hash] hash the hash to sign + def try_sign_with_parent_author(hash) + privkey = DiasporaFederation.callbacks.trigger( + :fetch_author_private_key_by_entity_guid, parent_type, parent_guid + ) + unless privkey.nil? + hash[:parent_author_signature] = sign_with_key(privkey, hash) + logger.info "event=sign_with_key signature=parent_author_signature guid=#{guid}" + end + end + # this happens only on downstream federation - def verify_parent_signature + def verify_parent_author_signature pubkey = DiasporaFederation.callbacks.trigger(:fetch_author_public_key_by_entity_guid, parent_type, parent_guid) - raise SignatureVerificationFailed, "failed to fetch public key for author of #{parent_guid}" if pubkey.nil? - raise SignatureVerificationFailed, "wrong parent_author_signature" unless Signing.verify_signature( - data, parent_author_signature, pubkey - ) + raise PublicKeyNotFound, "parent_author_signature parent_guid=#{parent_guid} guid=#{guid}" if pubkey.nil? + unless verify_signature(pubkey, parent_author_signature) + raise SignatureVerificationFailed, "wrong parent_author_signature parent_guid=#{parent_guid}" + end + end + + # Sign the data with the key + # + # @param [OpenSSL::PKey::RSA] privkey An RSA key + # @param [Hash] hash data to sign + # @return [String] A Base64 encoded signature of #signable_string with key + def sign_with_key(privkey, hash) + Base64.strict_encode64(privkey.sign(DIGEST, signable_string(hash))) + end + + # Check that signature is a correct signature + # + # @param [OpenSSL::PKey::RSA] pubkey An RSA key + # @param [String] signature The signature to be verified. + # @return [Boolean] + def verify_signature(pubkey, signature) + if signature.nil? + logger.warn "event=verify_signature status=abort reason=no_signature guid=#{guid}" + return false + end + + validity = pubkey.verify(DIGEST, Base64.decode64(signature), signable_string(data)) + logger.info "event=verify_signature status=complete guid=#{guid} validity=#{validity}" + validity + end + + # @param [Hash] hash data to sign + # @return [String] signature data string + def signable_string(hash) + hash.map {|name, value| + value.to_s unless name =~ /signature/ + }.compact.join(";") + end + + # Exception raised when creating the author_signature failes, because the private key was not found + class AuthorPrivateKeyNotFound < RuntimeError + end + + # Exception raised when verify_signatures fails to verify signatures (no public key found) + class PublicKeyNotFound < RuntimeError + end + + # Exception raised when verify_signatures fails to verify signatures (signatures are wrong) + class SignatureVerificationFailed < RuntimeError end end end diff --git a/lib/diaspora_federation/entities/signed_retraction.rb b/lib/diaspora_federation/entities/signed_retraction.rb index 9e16495..f763e85 100644 --- a/lib/diaspora_federation/entities/signed_retraction.rb +++ b/lib/diaspora_federation/entities/signed_retraction.rb @@ -64,7 +64,7 @@ module DiasporaFederation # @param [SignedRetraction, RelayableRetraction] ret the retraction to sign # @return [String] a Base64 encoded signature of the retraction with the key def self.sign_with_key(privkey, ret) - Base64.strict_encode64(privkey.sign(OpenSSL::Digest::SHA256.new, [ret.target_guid, ret.target_type].join(";"))) + Base64.strict_encode64(privkey.sign(Relayable::DIGEST, [ret.target_guid, ret.target_type].join(";"))) end end end diff --git a/lib/diaspora_federation/federation/exceptions.rb b/lib/diaspora_federation/federation/exceptions.rb index ea8c856..437d0cb 100644 --- a/lib/diaspora_federation/federation/exceptions.rb +++ b/lib/diaspora_federation/federation/exceptions.rb @@ -1,11 +1,11 @@ module DiasporaFederation module Federation # Raised if failed to fetch a public key of the sender of the received message - class SenderKeyNotFound < Exception + class SenderKeyNotFound < RuntimeError end # Raised if recipient private key is missing for a private receive - class RecipientKeyNotFound < Exception + class RecipientKeyNotFound < RuntimeError end end end diff --git a/lib/diaspora_federation/signing.rb b/lib/diaspora_federation/signing.rb deleted file mode 100644 index 8daaa2a..0000000 --- a/lib/diaspora_federation/signing.rb +++ /dev/null @@ -1,55 +0,0 @@ -module DiasporaFederation - # this module defines operations of signing an arbitrary hash with an arbitrary key - module Signing - extend Logging - - # Sign the data with the key - # - # @param [Hash] hash data to sign - # @param [OpenSSL::PKey::RSA] privkey An RSA key - # @return [String] A Base64 encoded signature of #signable_string with key - def self.sign_with_key(hash, privkey) - sig = Base64.strict_encode64( - privkey.sign( - OpenSSL::Digest::SHA256.new, - signable_string(hash) - ) - ) - logger.info "event=sign_with_key status=complete guid=#{hash[:guid]}" - sig - end - - # Check that signature is a correct signature - # - # @param [Hash] hash data to verify - # @param [String] signature The signature to be verified. - # @param [OpenSSL::PKey::RSA] pubkey An RSA key - # @return [Boolean] - def self.verify_signature(hash, signature, pubkey) - if pubkey.nil? - logger.warn "event=verify_signature status=abort reason=no_key guid=#{hash[:guid]}" - return false - elsif signature.nil? - logger.warn "event=verify_signature status=abort reason=no_signature guid=#{hash[:guid]}" - return false - end - - validity = pubkey.verify( - OpenSSL::Digest::SHA256.new, - Base64.decode64(signature), - signable_string(hash) - ) - logger.info "event=verify_signature status=complete guid=#{hash[:guid]} validity=#{validity}" - validity - end - - # @param [Hash] hash data to sign - # @return [String] signature data string - def self.signable_string(hash) - hash.map {|name, value| - value.to_s unless name =~ /signature/ - }.compact.join(";") - end - private_class_method :signable_string - end -end diff --git a/spec/lib/diaspora_federation/entities/relayable_retraction_spec.rb b/spec/lib/diaspora_federation/entities/relayable_retraction_spec.rb index 18aba1b..b498c1b 100644 --- a/spec/lib/diaspora_federation/entities/relayable_retraction_spec.rb +++ b/spec/lib/diaspora_federation/entities/relayable_retraction_spec.rb @@ -31,12 +31,12 @@ XML :fetch_private_key_by_diaspora_id, hash[:diaspora_id] ).and_return(author_pkey) + signed_string = "#{hash[:target_guid]};#{hash[:target_type]}" + signed_hash = Entities::RelayableRetraction.new(hash).to_h - signable_hash = hash.select do |key, _| - %i(target_guid target_type).include?(key) - end - expect(Signing.verify_signature(signable_hash, signed_hash[:target_author_signature], author_pkey)).to be_truthy + signature = Base64.decode64(signed_hash[:target_author_signature]) + expect(author_pkey.verify(OpenSSL::Digest::SHA256.new, signature, signed_string)).to be_truthy end it "updates parent author signature when it was nil, key was supplied and sender is not author of the target" do @@ -48,12 +48,12 @@ XML :fetch_private_key_by_diaspora_id, hash[:diaspora_id] ).and_return(author_pkey) + signed_string = "#{hash[:target_guid]};#{hash[:target_type]}" + signed_hash = Entities::RelayableRetraction.new(hash).to_h - signable_hash = hash.select do |key, _| - %i(target_guid target_type).include?(key) - end - expect(Signing.verify_signature(signable_hash, signed_hash[:parent_author_signature], author_pkey)).to be_truthy + signature = Base64.decode64(signed_hash[:parent_author_signature]) + expect(author_pkey.verify(OpenSSL::Digest::SHA256.new, signature, signed_string)).to be_truthy end it "doesn't change signatures if they are already set" do diff --git a/spec/lib/diaspora_federation/entities/relayable_spec.rb b/spec/lib/diaspora_federation/entities/relayable_spec.rb index 3a75702..114e5d0 100644 --- a/spec/lib/diaspora_federation/entities/relayable_spec.rb +++ b/spec/lib/diaspora_federation/entities/relayable_spec.rb @@ -4,6 +4,7 @@ module DiasporaFederation let(:parent_pkey) { OpenSSL::PKey::RSA.generate(1024) } let(:hash) { { + guid: FactoryGirl.generate(:guid), diaspora_id: FactoryGirl.generate(:diaspora_id), parent_guid: FactoryGirl.generate(:guid), some_other_data: "a_random_string" @@ -11,33 +12,39 @@ module DiasporaFederation } class SomeRelayable < Entity - include Entities::Relayable - + property :guid property :diaspora_id, xml_name: :diaspora_handle + include Entities::Relayable + def parent_type - "Target" + "Parent" end end + def legacy_sign_with_key(privkey, hash) + Base64.strict_encode64(privkey.sign(OpenSSL::Digest::SHA256.new, hash.values.join(";"))) + end + describe "#verify_signatures" do it "doesn't raise anything if correct data were passed" do - hash[:author_signature] = Signing.sign_with_key(hash, author_pkey) - hash[:parent_author_signature] = Signing.sign_with_key(hash, parent_pkey) + signed_hash = hash.dup + signed_hash[:author_signature] = legacy_sign_with_key(author_pkey, hash) + signed_hash[:parent_author_signature] = legacy_sign_with_key(parent_pkey, hash) expect(DiasporaFederation.callbacks).to receive(:trigger).with( :fetch_public_key_by_diaspora_id, hash[:diaspora_id] ).and_return(author_pkey.public_key) expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :fetch_author_public_key_by_entity_guid, "Target", hash[:parent_guid] + :fetch_author_public_key_by_entity_guid, "Parent", hash[:parent_guid] ).and_return(parent_pkey.public_key) expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :entity_author_is_local?, "Target", hash[:parent_guid] + :entity_author_is_local?, "Parent", hash[:parent_guid] ).and_return(false) - expect { SomeRelayable.new(hash).verify_signatures }.not_to raise_error + expect { SomeRelayable.new(signed_hash).verify_signatures }.not_to raise_error end it "raises when no public key for author was fetched" do @@ -47,7 +54,7 @@ module DiasporaFederation expect { SomeRelayable.new(hash).verify_signatures - }.to raise_error Entities::Relayable::SignatureVerificationFailed + }.to raise_error Entities::Relayable::PublicKeyNotFound end it "raises when bad author signature was passed" do @@ -63,27 +70,27 @@ module DiasporaFederation end it "raises when no public key for parent author was fetched" do - hash[:author_signature] = Signing.sign_with_key(hash, author_pkey) + hash[:author_signature] = legacy_sign_with_key(author_pkey, hash) expect(DiasporaFederation.callbacks).to receive(:trigger).with( :fetch_public_key_by_diaspora_id, hash[:diaspora_id] ).and_return(author_pkey.public_key) expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :fetch_author_public_key_by_entity_guid, "Target", hash[:parent_guid] + :fetch_author_public_key_by_entity_guid, "Parent", hash[:parent_guid] ).and_return(nil) expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :entity_author_is_local?, "Target", hash[:parent_guid] + :entity_author_is_local?, "Parent", hash[:parent_guid] ).and_return(false) expect { SomeRelayable.new(hash).verify_signatures - }.to raise_error Entities::Relayable::SignatureVerificationFailed + }.to raise_error Entities::Relayable::PublicKeyNotFound end it "raises when bad parent author signature was passed" do - hash[:author_signature] = Signing.sign_with_key(hash, author_pkey) + hash[:author_signature] = legacy_sign_with_key(author_pkey, hash) hash[:parent_author_signature] = nil expect(DiasporaFederation.callbacks).to receive(:trigger).with( @@ -91,11 +98,11 @@ module DiasporaFederation ).and_return(author_pkey.public_key) expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :fetch_author_public_key_by_entity_guid, "Target", hash[:parent_guid] + :fetch_author_public_key_by_entity_guid, "Parent", hash[:parent_guid] ).and_return(parent_pkey.public_key) expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :entity_author_is_local?, "Target", hash[:parent_guid] + :entity_author_is_local?, "Parent", hash[:parent_guid] ).and_return(false) expect { @@ -104,7 +111,7 @@ module DiasporaFederation end it "doesn't raise if parent_author_signature isn't set but we're on upstream federation" do - hash[:author_signature] = Signing.sign_with_key(hash, author_pkey) + hash[:author_signature] = legacy_sign_with_key(author_pkey, hash) hash[:parent_author_signature] = nil expect(DiasporaFederation.callbacks).to receive(:trigger).with( @@ -112,7 +119,7 @@ module DiasporaFederation ).and_return(author_pkey.public_key) expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :entity_author_is_local?, "Target", hash[:parent_guid] + :entity_author_is_local?, "Parent", hash[:parent_guid] ).and_return(true) expect { SomeRelayable.new(hash).verify_signatures }.not_to raise_error @@ -126,13 +133,19 @@ module DiasporaFederation ).and_return(author_pkey) expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :fetch_author_private_key_by_entity_guid, "Target", hash[:parent_guid] + :fetch_author_private_key_by_entity_guid, "Parent", hash[:parent_guid] ).and_return(parent_pkey) + signed_string = hash.reject {|key, _| key == :some_other_data }.values.join(";") + signed_hash = SomeRelayable.new(hash).to_h - expect(Signing.verify_signature(signed_hash, signed_hash[:author_signature], author_pkey)).to be_truthy - expect(Signing.verify_signature(signed_hash, signed_hash[:parent_author_signature], parent_pkey)).to be_truthy + def verify_signature(pubkey, signature, signed_string) + pubkey.verify(OpenSSL::Digest::SHA256.new, Base64.decode64(signature), signed_string) + end + + expect(verify_signature(author_pkey, signed_hash[:author_signature], signed_string)).to be_truthy + expect(verify_signature(parent_pkey, signed_hash[:parent_author_signature], signed_string)).to be_truthy end it "doesn't change signatures if they are already set" do @@ -141,18 +154,27 @@ module DiasporaFederation expect(SomeRelayable.new(hash).to_h).to eq(hash) end - it "doesn't change signatures if keys weren't supplied" do + it "raises when author_signature not set and key isn't supplied" do expect(DiasporaFederation.callbacks).to receive(:trigger).with( :fetch_private_key_by_diaspora_id, hash[:diaspora_id] ).and_return(nil) + expect { + SomeRelayable.new(hash).to_h + }.to raise_error Entities::Relayable::AuthorPrivateKeyNotFound + end + + it "doesn't set parent_author_signature if key isn't supplied" do expect(DiasporaFederation.callbacks).to receive(:trigger).with( - :fetch_author_private_key_by_entity_guid, "Target", hash[:parent_guid] + :fetch_private_key_by_diaspora_id, hash[:diaspora_id] + ).and_return(author_pkey) + + expect(DiasporaFederation.callbacks).to receive(:trigger).with( + :fetch_author_private_key_by_entity_guid, "Parent", hash[:parent_guid] ).and_return(nil) signed_hash = SomeRelayable.new(hash).to_h - expect(signed_hash[:author_signature]).to eq(nil) expect(signed_hash[:parent_author_signature]).to eq(nil) end end diff --git a/spec/lib/diaspora_federation/entities/signed_retraction_spec.rb b/spec/lib/diaspora_federation/entities/signed_retraction_spec.rb index f33da7c..7823995 100644 --- a/spec/lib/diaspora_federation/entities/signed_retraction_spec.rb +++ b/spec/lib/diaspora_federation/entities/signed_retraction_spec.rb @@ -26,13 +26,14 @@ XML :fetch_private_key_by_diaspora_id, hash[:diaspora_id] ).and_return(author_pkey) - signable_hash = hash.select do |key, _| - %i(target_guid target_type).include?(key) - end + signed_string = "#{hash[:target_guid]};#{hash[:target_type]}" signed_hash = Entities::SignedRetraction.new(hash).to_h - expect(Signing.verify_signature(signable_hash, signed_hash[:target_author_signature], author_pkey)).to be_truthy + valid = author_pkey.verify( + OpenSSL::Digest::SHA256.new, Base64.decode64(signed_hash[:target_author_signature]), signed_string + ) + expect(valid).to be_truthy end it "doesn't change signature if it is already set" do diff --git a/spec/lib/diaspora_federation/salmon/xml_payload_spec.rb b/spec/lib/diaspora_federation/salmon/xml_payload_spec.rb index 309408a..c60bee9 100644 --- a/spec/lib/diaspora_federation/salmon/xml_payload_spec.rb +++ b/spec/lib/diaspora_federation/salmon/xml_payload_spec.rb @@ -147,8 +147,11 @@ XML it "calls signatures verification on relayable unpack" do entity = FactoryGirl.build(:comment_entity) payload = Salmon::XmlPayload.pack(entity) - expect(Signing).to receive(:verify_signature).twice.and_call_original - Salmon::XmlPayload.unpack(payload) + payload.at_xpath("post/*[1]/author_signature").content = nil + + expect { + Salmon::XmlPayload.unpack(payload) + }.to raise_error DiasporaFederation::Entities::Relayable::SignatureVerificationFailed end end diff --git a/spec/lib/diaspora_federation/signing_spec.rb b/spec/lib/diaspora_federation/signing_spec.rb deleted file mode 100644 index 438d62c..0000000 --- a/spec/lib/diaspora_federation/signing_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -module DiasporaFederation - describe Signing do - let(:privkey) { - OpenSSL::PKey::RSA.new <<-RSA ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDT7vBTAl0Z55bPcBjM9dvSOTuVtBxsgfrw2W0hTAYpd1H5032C -cVW3mqd0l/9BHscgudVFAkvp+nf+wTQILn4qH4YAhOdWgrlSBA6Rbs3cmtmXzGNq -oQr4NOMbqs6sP+bBjDuDdB+cAFms/NDUH3cHBKPXi3e3csxiErmN1zyfWwIDAQAB -AoGAbpBC1CtxgqgtJz8l0ReafIvbJ/h0s68DyU7E/g/5TvyuyZSp77lMrKKEJfF9 -+u0hmVMZjgzqqcA/haopiPMoYcJAwwhJLeXAgAWA+8j60Y524WLDcMPwMxQvVFd9 -3FYXdOalojDoS34BWeBy6Gt+lLGyDvo/NnJBqIMPN0/KzYECQQDuslE4f1+RHhUq -wf2rL/7gCgrnkDOcH1SPjN2FrKG5ALmjThCq7Wr1Umj81uvmglfpIRY/ORgYgujA -kwNTB1ohAkEA40v0mHaYDegL//jucFmx/iK9Bs/722rJGIXI7bGIwLRC1hW101h3 -DLMEMT0QaamVEEnrXFdqhjz+bfYfqUkh+wJAU3a+t8ayIAgo1p6mmKlbsfNRBM+D -fF/oLZnQC+HlWs9KGjQ918bU05tRYre0HRIOs1ICeXD5X/jGci/1xZ6YgQJAJony -Zwd0sKbvoe8rPpF2xIhPVKBfK8znW+kTMHoxnbryuinkMnmFdfnEdDTOW5wNUj22 -Umnf/fLJkQtyQtnLkQJBANMoQPrP6aMRh45bhq+y6DbzHHHc2T5cuGBCtnhu+qrK -hWHXqQT4rArfq8YBpvDUa7qD13WwFGK3TPRpQSVGzNg= ------END RSA PRIVATE KEY----- -RSA - } - - let(:hash) { - { - param1: "1", - param2: "2", - signature: "SIGNATURE_VALUE==", - param3: "3", - parent_signature: "SIGNATURE2_VALUE==", - param4: "4" - } - } - let(:signature) { - "OesXlpesuLcA0t8gPyBjvznvkl0pz63p8z6+o2fxFNUaZkuR6YQv/sJOTSMPYBAFwcWr048Ol7yw4jSHq0gFCdBBeF7Mg287jktCie"\ - "xa6G6mA24hBlOWnyRJLV2OyqcTU1P5pXWlUc1Mbwbr6bSIs6VK9djFMLLQ6wjjpusJ0XU=" - } - - describe ".signable_string" do - it "forms correct string for a hash" do - expect(Signing.send(:signable_string, hash)).to eq("1;2;3;4") - end - end - - describe ".sign_with_key" do - it "produces correct signature" do - expect(Signing.sign_with_key(hash, privkey)).to eq(signature) - end - end - - describe ".verify_signature" do - it "verifies correct signature" do - expect(Signing.verify_signature(hash, signature, privkey.public_key)).to be_truthy - end - - it "doesn't verify wrong signature" do - expect(Signing.verify_signature(hash, "false signature==", privkey.public_key)).to be_falsy - end - - it "doesn't verify when signature is missing" do - expect(Signing.verify_signature(hash, nil, privkey.public_key)).to be_falsy - end - - it "doesn't verify when public key is missing" do - expect(Signing.verify_signature(hash, signature, nil)).to be_falsy - end - end - end -end diff --git a/spec/support/shared_entity_specs.rb b/spec/support/shared_entity_specs.rb index 1f02a56..f724180 100644 --- a/spec/support/shared_entity_specs.rb +++ b/spec/support/shared_entity_specs.rb @@ -75,17 +75,20 @@ shared_examples "a relayable Entity" do let(:instance) { described_class.new(data.merge(author_signature: nil, parent_author_signature: nil)) } context "signatures generation" do + def legacy_verify_signature(pubkey, signature, signed_string) + pubkey.verify(OpenSSL::Digest::SHA256.new, Base64.decode64(signature), signed_string) + end + it "computes correct signatures for the entity" do - hash = instance.to_h + signed_string = instance.to_h.map {|name, value| value.to_s unless name =~ /signature/ }.compact.join(";") + xml = DiasporaFederation::Salmon::XmlPayload.pack(instance) author_signature = xml.at_xpath("post/*[1]/author_signature").text parent_author_signature = xml.at_xpath("post/*[1]/parent_author_signature").text - expect(DiasporaFederation::Signing.verify_signature(hash, author_signature, test_pkey)) - .to be_truthy - expect(DiasporaFederation::Signing.verify_signature(hash, parent_author_signature, test_pkey)) - .to be_truthy + expect(legacy_verify_signature(test_pkey, author_signature, signed_string)).to be_truthy + expect(legacy_verify_signature(test_pkey, parent_author_signature, signed_string)).to be_truthy end end end