improve magic envelope validation

This commit is contained in:
Benjamin Neff 2016-08-01 02:41:28 +02:00
parent 52af7e4538
commit 90d12e71d0
3 changed files with 93 additions and 26 deletions

View file

@ -33,6 +33,10 @@ module DiasporaFederation
class InvalidSignature < RuntimeError
end
# Raised, if the parsed Magic Envelope specifies an unhandled data type.
class InvalidDataType < RuntimeError
end
# Raised, if the parsed Magic Envelope specifies an unhandled algorithm.
class InvalidAlgorithm < RuntimeError
end

View file

@ -110,19 +110,20 @@ module DiasporaFederation
# @raise [ArgumentError] if any of the arguments is of invalid type
# @raise [InvalidEnvelope] if the envelope XML structure is malformed
# @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
# @raise [InvalidDataType] if the data is missing or unsupported
# @raise [InvalidEncoding] if the data is wrongly encoded or encoding is missing
# @raise [InvalidAlgorithm] if the algorithm is missing or doesn't match
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)
validate_envelope(magic_env)
validate_type(magic_env)
validate_encoding(magic_env)
validate_algorithm(magic_env)
sender ||= sender(magic_env)
raise InvalidSignature unless signature_valid?(magic_env, sender)
raise InvalidEncoding unless encoding_valid?(magic_env)
raise InvalidAlgorithm unless algorithm_valid?(magic_env)
data = read_and_decrypt_data(magic_env, cipher_params)
logger.debug "unenvelop message from #{sender}:\n#{data}"
@ -165,11 +166,20 @@ module DiasporaFederation
end
# @param [Nokogiri::XML::Element] env magic envelope XML
private_class_method def self.envelope_valid?(env)
(env.instance_of?(Nokogiri::XML::Element) &&
env.name == "env" &&
!env.at_xpath("me:data").content.empty? &&
!env.at_xpath("me:sig").content.empty?)
# @raise [InvalidEnvelope] if the envelope XML structure is malformed
private_class_method def self.validate_envelope(env)
raise InvalidEnvelope unless env.instance_of?(Nokogiri::XML::Element) && env.name == "env"
validate_element(env, "me:data")
validate_element(env, "me:sig")
end
# @param [Nokogiri::XML::Element] env magic envelope XML
# @param [String] xpath the element to validate
# @raise [InvalidEnvelope] if the element is missing or empty
private_class_method def self.validate_element(env, xpath)
element = env.at_xpath(xpath)
raise InvalidEnvelope, "missing #{xpath}" unless element
raise InvalidEnvelope, "empty #{xpath}" if element.content.empty?
end
# @param [Nokogiri::XML::Element] env magic envelope XML
@ -207,15 +217,27 @@ module DiasporaFederation
end
# @param [Nokogiri::XML::Element] magic_env magic envelope XML
# @return [Boolean]
private_class_method def self.encoding_valid?(magic_env)
magic_env.at_xpath("me:encoding").content == ENCODING
# @raise [InvalidDataType] if the data is missing or unsupported
private_class_method def self.validate_type(magic_env)
type = magic_env.at_xpath("me:data")["type"]
raise InvalidDataType, "missing data type" if type.nil?
raise InvalidDataType, "invalid data type: #{type}" unless type == DATA_TYPE
end
# @param [Nokogiri::XML::Element] magic_env magic envelope XML
# @return [Boolean]
private_class_method def self.algorithm_valid?(magic_env)
magic_env.at_xpath("me:alg").content == ALGORITHM
# @raise [InvalidEncoding] if the data is wrongly encoded or encoding is missing
private_class_method def self.validate_encoding(magic_env)
enc = magic_env.at_xpath("me:encoding")
raise InvalidEncoding, "missing encoding" unless enc
raise InvalidEncoding, "invalid encoding: #{enc.content}" unless enc.content == ENCODING
end
# @param [Nokogiri::XML::Element] magic_env magic envelope XML
# @raise [InvalidAlgorithm] if the algorithm is missing or doesn't match
private_class_method def self.validate_algorithm(magic_env)
alg = magic_env.at_xpath("me:alg")
raise InvalidAlgorithm, "missing algorithm" unless alg
raise InvalidAlgorithm, "invalid algorithm: #{alg.content}" unless alg.content == ALGORITHM
end
# @param [Nokogiri::XML::Element] magic_env magic envelope XML

View file

@ -110,11 +110,6 @@ module DiasporaFederation
).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
end
it "works with sane input" do
expect {
Salmon::MagicEnvelope.unenvelop(envelope.envelop(privkey), sender)
@ -135,6 +130,14 @@ module DiasporaFederation
}.to raise_error Salmon::InvalidEnvelope
end
it "raises if missing signature" do
bad_env = envelope.envelop(privkey)
bad_env.at_xpath("me:sig").remove
expect {
Salmon::MagicEnvelope.unenvelop(bad_env, sender)
}.to raise_error Salmon::InvalidEnvelope, "missing me:sig"
end
it "verifies the signature" do
other_sender = FactoryGirl.generate(:diaspora_id)
other_key = OpenSSL::PKey::RSA.generate(512)
@ -146,22 +149,60 @@ module DiasporaFederation
}.to raise_error Salmon::InvalidSignature
end
it "raises if missing data" do
bad_env = envelope.envelop(privkey)
bad_env.at_xpath("me:data").remove
expect {
Salmon::MagicEnvelope.unenvelop(bad_env, sender)
}.to raise_error Salmon::InvalidEnvelope, "missing me:data"
end
it "raises if missing encoding" do
bad_env = envelope.envelop(privkey)
bad_env.at_xpath("me:encoding").remove
expect {
Salmon::MagicEnvelope.unenvelop(bad_env, sender)
}.to raise_error Salmon::InvalidEncoding, "missing encoding"
end
it "verifies the encoding" do
bad_env = envelope.envelop(privkey)
bad_env.at_xpath("me:encoding").content = "invalid_enc"
re_sign(bad_env, privkey)
expect {
Salmon::MagicEnvelope.unenvelop(bad_env, sender)
}.to raise_error Salmon::InvalidEncoding
}.to raise_error Salmon::InvalidEncoding, "invalid encoding: invalid_enc"
end
it "raises if missing algorithm" do
bad_env = envelope.envelop(privkey)
bad_env.at_xpath("me:alg").remove
expect {
Salmon::MagicEnvelope.unenvelop(bad_env, sender)
}.to raise_error Salmon::InvalidAlgorithm, "missing algorithm"
end
it "verifies the algorithm" do
bad_env = envelope.envelop(privkey)
bad_env.at_xpath("me:alg").content = "invalid_alg"
re_sign(bad_env, privkey)
expect {
Salmon::MagicEnvelope.unenvelop(bad_env, sender)
}.to raise_error Salmon::InvalidAlgorithm
}.to raise_error Salmon::InvalidAlgorithm, "invalid algorithm: invalid_alg"
end
it "raises if missing data type" do
bad_env = envelope.envelop(privkey)
bad_env.at_xpath("me:data").attributes["type"].remove
expect {
Salmon::MagicEnvelope.unenvelop(bad_env, sender)
}.to raise_error Salmon::InvalidDataType, "missing data type"
end
it "verifies the data type" do
bad_env = envelope.envelop(privkey)
bad_env.at_xpath("me:data")["type"] = "invalid_type"
expect {
Salmon::MagicEnvelope.unenvelop(bad_env, sender)
}.to raise_error Salmon::InvalidDataType, "invalid data type: invalid_type"
end
end