improve magic envelope validation
This commit is contained in:
parent
52af7e4538
commit
90d12e71d0
3 changed files with 93 additions and 26 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue