Method: XMLSecurity::SignedDocument#validate_doc

Defined in:
lib/xml_security.rb

#validate_doc(base64_cert, soft = true) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/xml_security.rb', line 64

def validate_doc(base64_cert, soft = true)
  # validate references

  # check for inclusive namespaces
  inclusive_namespaces = extract_inclusive_namespaces

  document = Nokogiri.parse(self.to_s)

  # store and remove signature node
  self.sig_element ||= begin
    element = REXML::XPath.first(self, "//ds:Signature", {"ds"=>DSIG})
    element.remove
  end


  # verify signature
  signed_info_element     = REXML::XPath.first(sig_element, "//ds:SignedInfo", {"ds"=>DSIG})
  self.noko_sig_element ||= document.at_xpath('//ds:Signature', 'ds' => DSIG)
  noko_signed_info_element = noko_sig_element.at_xpath('./ds:SignedInfo', 'ds' => DSIG)
  canon_algorithm = canon_algorithm REXML::XPath.first(sig_element, '//ds:CanonicalizationMethod')
  canon_string = noko_signed_info_element.canonicalize(canon_algorithm)
  noko_sig_element.remove

  # check digests
  REXML::XPath.each(sig_element, "//ds:Reference", {"ds"=>DSIG}) do |ref|
    uri                           = ref.attributes.get_attribute("URI").value

    hashed_element                = document.at_xpath("//*[@ID='#{uri[1..-1]}']")
    canon_algorithm               = canon_algorithm REXML::XPath.first(ref, '//ds:CanonicalizationMethod')
    canon_hashed_element          = hashed_element.canonicalize(canon_algorithm, inclusive_namespaces).gsub('&','&')

    digest_algorithm              = algorithm(REXML::XPath.first(ref, "//ds:DigestMethod"))

    hash                          = digest_algorithm.digest(canon_hashed_element)
    digest_value                  = Base64.decode64(REXML::XPath.first(ref, "//ds:DigestValue", {"ds"=>DSIG}).text)

    unless digests_match?(hash, digest_value)
      return soft ? false : (raise FederazioneTrentina::Saml::ValidationError.new("Digest mismatch"))
    end
  end

  base64_signature        = REXML::XPath.first(sig_element, "//ds:SignatureValue", {"ds"=>DSIG}).text
  signature               = Base64.decode64(base64_signature)

  # get certificate object
  cert_text               = Base64.decode64(base64_cert)
  cert                    = OpenSSL::X509::Certificate.new(cert_text)

  # signature method
  signature_algorithm     = algorithm(REXML::XPath.first(signed_info_element, "//ds:SignatureMethod", {"ds"=>DSIG}))

  unless cert.public_key.verify(signature_algorithm.new, signature, canon_string)
    return soft ? false : (raise FederazioneTrentina::Saml::ValidationError.new("Key validation error"))
  end

  return true
end