module SAML2::Signable
def sign(x509_certificate, private_key, algorithm_name = :sha256)
-
(self)-
Parameters:
-
algorithm_name(Symbol) -- -
private_key(String) -- -
x509_certificate(String) --
def sign(x509_certificate, private_key, algorithm_name = :sha256) to_xml xml = @document.root xml.set_id_attribute('ID') xml.sign!(cert: x509_certificate, key: private_key, digest_alg: algorithm_name.to_s, signature_alg: "rsa-#{algorithm_name}", uri: "##{id}") # the Signature element must be the first element signature = xml.at_xpath("dsig:Signature", Namespaces::ALL) xml.children.first.add_previous_sibling(signature) self end
def signature
-
(Nokogiri::XML::Element, nil)-
def signature unless instance_variable_defined?(:@signature) @signature = xml.at_xpath('dsig:Signature', Namespaces::ALL) if @signature signed_node = @signature.at_xpath('dsig:SignedInfo/dsig:Reference', Namespaces::ALL)['URI'] if signed_node == '' @signature = nil unless xml == xml.document.root elsif signed_node != "##{xml['ID']}" @signature = nil else # validating the schema will automatically add ID attributes, so check that first xml.set_id_attribute('ID') unless xml.document.get_id(xml['ID']) end end end @signature end
def signed?
def signed? !!signature end
def signing_key
-
(KeyInfo, nil)-
def signing_key @signing_key ||= KeyInfo.from_xml(signature) end
def valid_signature?(fingerprint: nil, cert: nil, verification_time: nil)
-
(Boolean)-
Parameters:
-
() --
def valid_signature?(fingerprint: nil, cert: nil, verification_time: nil) validate_signature(fingerprint: fingerprint, cert: cert, verification_time: verification_time).empty? end
def validate_signature(fingerprint: nil,
-
(Array- An empty array on success, details of errors on failure.)
Parameters:
-
allow_expired_certificate(Boolean) -- -
cert() -- optional [Array, String] -
fingerprint() -- optional [Array, String]
def validate_signature(fingerprint: nil, cert: nil, verification_time: nil, allow_expired_certificate: false) return ["not signed"] unless signed? certs = Array(cert) certs = certs.dup if certs.equal?(cert) # see if any given fingerprints match the certificate embedded in the XML; # if so, extract the certificate, and add it to the allowed certificates list Array(fingerprint).each do |fp| certs << signing_key.certificate if signing_key&.fingerprint == KeyInfo.format_fingerprint(fp) end certs = certs.uniq return ["no trusted certificate found"] if certs.empty? verify_certificate = true if signing_key signing_cert = signing_key.certificate if allow_expired_certificate verification_time = signing_cert.not_after - 1 end # we explicitly trust the signing certificate, but it's not self-signed; # xmlsec is weird and decides not to trust it in that case, so we skip # certificate verification by xmlsec, and do it ourselves if certs.include?(signing_cert) && signing_cert.issuer != signing_cert.subject verification_time ||= Time.now.utc return ["certificate has expired"] if verification_time > signing_cert.not_after return ["certificate is not yet valid"] if verification_time < signing_cert.not_before verify_certificate = false end end begin result = signature.verify_with(certs: certs, verification_time: verification_time, verify_certificates: verify_certificate) result ? [] : ["signature is invalid"] rescue XMLSec::VerificationError => e [e.message] end end