From 3a83dc97ac6b1b32089e6a5269ffd92b3d951e83 Mon Sep 17 00:00:00 2001 From: Benjamin Neff Date: Sun, 20 Mar 2016 17:07:21 +0100 Subject: [PATCH] use author_id from slap to fetch pubkey in magic-env --- .../federation/receiver/slap_receiver.rb | 5 +-- .../salmon/magic_envelope.rb | 27 +++++++-------- lib/diaspora_federation/salmon/slap.rb | 6 ++-- .../salmon/magic_envelope_spec.rb | 34 +++++++++++++++---- spec/support/shared_slap_specs.rb | 16 +++------ 5 files changed, 48 insertions(+), 40 deletions(-) diff --git a/lib/diaspora_federation/federation/receiver/slap_receiver.rb b/lib/diaspora_federation/federation/receiver/slap_receiver.rb index 76cdb38..c036a74 100644 --- a/lib/diaspora_federation/federation/receiver/slap_receiver.rb +++ b/lib/diaspora_federation/federation/receiver/slap_receiver.rb @@ -14,10 +14,7 @@ module DiasporaFederation # Parse the salmon xml def parse - sender_id = slap.author_id - public_key = DiasporaFederation.callbacks.trigger(:fetch_public_key_by_diaspora_id, sender_id) - raise Salmon::SenderKeyNotFound if public_key.nil? - slap.entity(public_key) + slap.entity end end end diff --git a/lib/diaspora_federation/salmon/magic_envelope.rb b/lib/diaspora_federation/salmon/magic_envelope.rb index 8dfcbb5..08b8474 100644 --- a/lib/diaspora_federation/salmon/magic_envelope.rb +++ b/lib/diaspora_federation/salmon/magic_envelope.rb @@ -99,7 +99,7 @@ module DiasporaFederation # @see AES#decrypt # # @param [Nokogiri::XML::Element] magic_env XML root node of a magic envelope - # @param [OpenSSL::PKey::RSA] rsa_pubkey public key to verify the signature + # @param [String] sender diaspora-ID of the sender or nil # @param [Hash] cipher_params hash containing the key and iv for # AES-decrypting previously encrypted data. E.g.: { iv: "...", key: "..." } # @@ -110,11 +110,11 @@ module DiasporaFederation # @raise [InvalidSignature] if the signature can't be verified # @raise [InvalidEncoding] if the data is wrongly encoded # @raise [InvalidAlgorithm] if the algorithm used doesn't match - def self.unenvelop(magic_env, rsa_pubkey=nil, cipher_params=nil) + def self.unenvelop(magic_env, sender=nil, cipher_params=nil) raise ArgumentError unless magic_env.instance_of?(Nokogiri::XML::Element) raise InvalidEnvelope unless envelope_valid?(magic_env) - raise InvalidSignature unless signature_valid?(magic_env, rsa_pubkey) + raise InvalidSignature unless signature_valid?(magic_env, sender) raise InvalidEncoding unless encoding_valid?(magic_env) raise InvalidAlgorithm unless algorithm_valid?(magic_env) @@ -162,15 +162,18 @@ module DiasporaFederation private_class_method :envelope_valid? # @param [Nokogiri::XML::Element] env magic envelope XML - # @param [OpenSSL::PKey::RSA] pubkey public key or nil + # @param [String] sender diaspora-ID of the sender or nil # @return [Boolean] - def self.signature_valid?(env, pubkey) + def self.signature_valid?(env, sender) + sender ||= sender(env) + subject = sig_subject([Base64.urlsafe_decode64(env.at_xpath("me:data").content), env.at_xpath("me:data")["type"], env.at_xpath("me:encoding").content, env.at_xpath("me:alg").content]) - sender_key = pubkey || sender_key(env) + sender_key = DiasporaFederation.callbacks.trigger(:fetch_public_key_by_diaspora_id, sender) + raise SenderKeyNotFound unless sender_key sig = Base64.urlsafe_decode64(env.at_xpath("me:sig").content) sender_key.verify(DIGEST, sig, subject) @@ -179,17 +182,13 @@ module DiasporaFederation # reads the +key_id+ from the magic envelope # @param [Nokogiri::XML::Element] env magic envelope XML - # @return [OpenSSL::PKey::RSA] sender public key - def self.sender_key(env) + # @return [String] diaspora-ID of the sender + def self.sender(env) key_id = env.at_xpath("me:sig")["key_id"] raise InvalidEnvelope, "no key_id" unless key_id # TODO: move to `envelope_valid?` - sender = Base64.urlsafe_decode64(key_id) - - sender_key = DiasporaFederation.callbacks.trigger(:fetch_public_key_by_diaspora_id, sender) - raise SenderKeyNotFound unless sender_key - sender_key + Base64.urlsafe_decode64(key_id) end - private_class_method :sender_key + private_class_method :sender # constructs the signature subject. # the given array should consist of the data, data_type (mimetype), encoding diff --git a/lib/diaspora_federation/salmon/slap.rb b/lib/diaspora_federation/salmon/slap.rb index f6c0b65..800feb1 100644 --- a/lib/diaspora_federation/salmon/slap.rb +++ b/lib/diaspora_federation/salmon/slap.rb @@ -46,12 +46,10 @@ module DiasporaFederation # # @see MagicEnvelope.unenvelop # - # @param [OpenSSL::PKey::RSA] pubkey public key for validating the signature # @return [Entity] entity instance from the XML # @raise [ArgumentError] if the public key is of the wrong type - def entity(pubkey) - raise ArgumentError unless pubkey.instance_of?(OpenSSL::PKey::RSA) - MagicEnvelope.unenvelop(@magic_envelope, pubkey, @cipher_params) + def entity + MagicEnvelope.unenvelop(@magic_envelope, author_id, @cipher_params) end # Parses an unencrypted Salmon XML string and returns a new instance of diff --git a/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb b/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb index c967ce7..36ea707 100644 --- a/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb +++ b/spec/lib/diaspora_federation/salmon/magic_envelope_spec.rb @@ -104,6 +104,12 @@ module DiasporaFederation describe ".unenvelop" do context "sanity" do + before do + allow(DiasporaFederation.callbacks).to receive(:trigger).with( + :fetch_public_key_by_diaspora_id, sender + ).and_return(privkey.public_key) + end + def re_sign(env, key) new_sig = Base64.urlsafe_encode64(key.sign(OpenSSL::Digest::SHA256.new, sig_subj(env))) env.at_xpath("me:sig").content = new_sig @@ -111,7 +117,7 @@ module DiasporaFederation it "works with sane input" do expect { - Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), privkey.public_key) + Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), sender) }.not_to raise_error end @@ -125,14 +131,20 @@ module DiasporaFederation it "verifies the envelope structure" do expect { - Salmon::MagicEnvelope.unenvelop(Nokogiri::XML::Document.parse("").root, privkey.public_key) + Salmon::MagicEnvelope.unenvelop(Nokogiri::XML::Document.parse("").root, sender) }.to raise_error Salmon::InvalidEnvelope end it "verifies the signature" do + other_sender = FactoryGirl.generate(:diaspora_id) other_key = OpenSSL::PKey::RSA.generate(512) + + expect(DiasporaFederation.callbacks).to receive(:trigger).with( + :fetch_public_key_by_diaspora_id, other_sender + ).and_return(other_key) + expect { - Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), other_key.public_key) + Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), other_sender) }.to raise_error Salmon::InvalidSignature end @@ -141,7 +153,7 @@ module DiasporaFederation bad_env.at_xpath("me:encoding").content = "invalid_enc" re_sign(bad_env, privkey) expect { - Salmon::MagicEnvelope.unenvelop(bad_env, privkey.public_key) + Salmon::MagicEnvelope.unenvelop(bad_env, sender) }.to raise_error Salmon::InvalidEncoding end @@ -150,23 +162,31 @@ module DiasporaFederation bad_env.at_xpath("me:alg").content = "invalid_alg" re_sign(bad_env, privkey) expect { - Salmon::MagicEnvelope.unenvelop(bad_env, privkey.public_key) + Salmon::MagicEnvelope.unenvelop(bad_env, sender) }.to raise_error Salmon::InvalidAlgorithm end end it "returns the original entity" do - entity = Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), privkey.public_key) + allow(DiasporaFederation.callbacks).to receive(:trigger).with( + :fetch_public_key_by_diaspora_id, sender + ).and_return(privkey.public_key) + + entity = Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), sender) expect(entity).to be_an_instance_of Entities::TestEntity expect(entity.test).to eq("asdf") end it "decrypts on the fly, when cipher params are present" do + allow(DiasporaFederation.callbacks).to receive(:trigger).with( + :fetch_public_key_by_diaspora_id, sender + ).and_return(privkey.public_key) + params = envelope.encrypt! env_xml = envelope.envelop(privkey) - entity = Salmon::MagicEnvelope.unenvelop(env_xml, privkey.public_key, params) + entity = Salmon::MagicEnvelope.unenvelop(env_xml, sender, params) expect(entity).to be_an_instance_of Entities::TestEntity expect(entity.test).to eq("asdf") end diff --git a/spec/support/shared_slap_specs.rb b/spec/support/shared_slap_specs.rb index ca8d526..da15993 100644 --- a/spec/support/shared_slap_specs.rb +++ b/spec/support/shared_slap_specs.rb @@ -4,18 +4,12 @@ shared_examples "a Slap instance" do end context "#entity" do - it "requires the pubkey for the first time (to verify the signature)" do - expect { subject.entity }.to raise_error ArgumentError - end - - it "works when the pubkey is given" do - expect { - subject.entity(privkey.public_key) - }.not_to raise_error - end - it "returns the entity" do - entity = subject.entity(privkey.public_key) + allow(DiasporaFederation.callbacks).to receive(:trigger).with( + :fetch_public_key_by_diaspora_id, author_id + ).and_return(privkey.public_key) + + entity = subject.entity expect(entity).to be_an_instance_of DiasporaFederation::Entities::TestEntity expect(entity.test).to eq("qwertzuiop") end