# File lib/xml_security.rb, line 200 def validate_document(idp_cert_fingerprint, soft = true, options = {}) # get cert from response cert_element = REXML::XPath.first( self, "//ds:X509Certificate", { "ds"=>DSIG } ) if cert_element base64_cert = cert_element.text cert_text = Base64.decode64(base64_cert) begin cert = OpenSSL::X509::Certificate.new(cert_text) rescue OpenSSL::X509::CertificateError => e return append_error("Certificate Error", soft) end if options[:fingerprint_alg] fingerprint_alg = XMLSecurity::BaseDocument.new.algorithm(options[:fingerprint_alg]).new else fingerprint_alg = OpenSSL::Digest::SHA1.new end fingerprint = fingerprint_alg.hexdigest(cert.to_der) # check cert matches registered idp cert if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase @errors << "Fingerprint mismatch" return append_error("Fingerprint mismatch", soft) end else if options[:cert] base64_cert = Base64.encode64(options[:cert].to_pem) else if soft return false else return append_error("Certificate element missing in response (ds:X509Certificate) and not cert provided at settings", soft) end end end validate_signature(base64_cert, soft) end
# File lib/xml_security.rb, line 243 def validate_document_with_cert(idp_cert) # get cert from response cert_element = REXML::XPath.first( self, "//ds:X509Certificate", { "ds"=>DSIG } ) if cert_element base64_cert = cert_element.text cert_text = Base64.decode64(base64_cert) begin cert = OpenSSL::X509::Certificate.new(cert_text) rescue OpenSSL::X509::CertificateError => e return append_error("Certificate Error", soft) end # check saml response cert matches provided idp cert if idp_cert.to_pem != cert.to_pem return false end validate_signature(base64_cert, true) end end
# File lib/xml_security.rb, line 268 def validate_signature(base64_cert, soft = true) document = Nokogiri::XML(self.to_s) do |config| config.options = XMLSecurity::BaseDocument::NOKOGIRI_OPTIONS end # create a rexml document @working_copy ||= REXML::Document.new(self.to_s).root # get signature node sig_element = REXML::XPath.first( @working_copy, "//ds:Signature", {"ds"=>DSIG} ) # signature method sig_alg_value = REXML::XPath.first( sig_element, "./ds:SignedInfo/ds:SignatureMethod", {"ds"=>DSIG} ) signature_algorithm = algorithm(sig_alg_value) # get signature base64_signature = REXML::XPath.first( sig_element, "./ds:SignatureValue", {"ds" => DSIG} ).text signature = Base64.decode64(base64_signature) # canonicalization method canon_algorithm = canon_algorithm REXML::XPath.first( sig_element, './ds:SignedInfo/ds:CanonicalizationMethod', 'ds' => DSIG ) noko_sig_element = document.at_xpath('//ds:Signature', 'ds' => DSIG) noko_signed_info_element = noko_sig_element.at_xpath('./ds:SignedInfo', 'ds' => DSIG) canon_string = noko_signed_info_element.canonicalize(canon_algorithm) noko_sig_element.remove # get inclusive namespaces inclusive_namespaces = extract_inclusive_namespaces # check digests ref = REXML::XPath.first(sig_element, "//ds:Reference", {"ds"=>DSIG}) uri = ref.attributes.get_attribute("URI").value hashed_element = document.at_xpath("//*[@ID=$id]", nil, { 'id' => extract_signed_element_id }) canon_algorithm = canon_algorithm REXML::XPath.first( ref, '//ds:CanonicalizationMethod', { "ds" => DSIG } ) canon_hashed_element = hashed_element.canonicalize(canon_algorithm, inclusive_namespaces) digest_algorithm = algorithm(REXML::XPath.first( ref, "//ds:DigestMethod", { "ds" => DSIG } )) hash = digest_algorithm.digest(canon_hashed_element) encoded_digest_value = REXML::XPath.first( ref, "//ds:DigestValue", { "ds" => DSIG } ).text digest_value = Base64.decode64(encoded_digest_value) unless digests_match?(hash, digest_value) @errors << "Digest mismatch" return append_error("Digest mismatch", soft) end # get certificate object cert_text = Base64.decode64(base64_cert) cert = OpenSSL::X509::Certificate.new(cert_text) # verify signature unless cert.public_key.verify(signature_algorithm.new, signature, canon_string) return append_error("Key validation error", soft) end return true end
# File lib/xml_security.rb, line 191 def initialize(response, errors = []) super(response) @errors = errors end