class InovadoraXml::Assinador

Attributes

cert[RW]
errors[RW]
key[RW]
parametro[RW]
tag_assinar[RW]
xml_assinado[RW]
xml_assinar[RW]

Public Class Methods

new(xml, tag_assinar, cert, key) click to toggle source
# File lib/inovadora_xml/assinador.rb, line 6
def initialize(xml, tag_assinar, cert, key)
  self.errors = ActiveModel::Errors.new(self)

  self.xml_assinar = xml.to_s
  self.tag_assinar = tag_assinar
  self.cert        = cert
  self.key         = key
end

Public Instance Methods

assinar_xml() click to toggle source
# File lib/inovadora_xml/assinador.rb, line 15
def assinar_xml()
  if self.valid?
    chave_privada = OpenSSL::PKey::RSA.new(File.read(self.key))
    certificado = OpenSSL::X509::Certificate.new(File.read(self.cert))

    self.xml_assinado = Nokogiri::XML(self.xml_assinar.to_s, &:noblanks)
    self.xml_assinado.xpath("//xmlns:#{self.tag_assinar}").each do |node|

      # 1. Digest Hash for all XML
      xml_canon = node.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
      xml_digest = Base64.encode64(OpenSSL::Digest::SHA1.digest(xml_canon)).strip

      # 2. Add Signature Node
      signature = Nokogiri::XML::Node.new('Signature', self.xml_assinado)
      signature.default_namespace = 'http://www.w3.org/2000/09/xmldsig#'
      node.after(signature)

      # 3.1 Create Signature Info
      signature_info = Nokogiri::XML::Node.new('SignedInfo', self.xml_assinado)

      # 3.2 Add CanonicalizationMethod
      child_node = Nokogiri::XML::Node.new('CanonicalizationMethod', self.xml_assinado)
      child_node['Algorithm'] = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
      signature_info.add_child child_node

      # 3.3 Add SignatureMethod
      child_node = Nokogiri::XML::Node.new('SignatureMethod', self.xml_assinado)
      child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
      signature_info.add_child child_node

      # 3.4 Create Reference
      reference = Nokogiri::XML::Node.new('Reference', self.xml_assinado)
      reference['URI'] = "##{node.first.last}"

      # 3.5 Add Transforms
      transforms = Nokogiri::XML::Node.new('Transforms', self.xml_assinado)

      child_node  = Nokogiri::XML::Node.new('Transform', self.xml_assinado)
      child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
      transforms.add_child child_node

      child_node  = Nokogiri::XML::Node.new('Transform', self.xml_assinado)
      child_node['Algorithm'] = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'
      transforms.add_child child_node

      reference.add_child transforms

      # 3.6 Add Digest
      child_node  = Nokogiri::XML::Node.new('DigestMethod', self.xml_assinado)
      child_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#sha1'
      reference.add_child child_node

      # 3.6 Add DigestValue
      child_node  = Nokogiri::XML::Node.new('DigestValue', self.xml_assinado)
      child_node.content = xml_digest
      reference.add_child child_node

      # 3.7 Add Reference and Signature Info
      signature_info.add_child reference
      signature.add_child signature_info

      # 4 Sign Signature
      sign_canon = signature_info.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
      signature_hash = chave_privada.sign(OpenSSL::Digest::SHA1.new, sign_canon)
      signature_value = Base64.encode64(signature_hash).gsub("\n", '')

      # 4.1 Add SignatureValue
      child_node = Nokogiri::XML::Node.new('SignatureValue', self.xml_assinado)
      child_node.content = signature_value
      signature.add_child child_node

      # 5 Create KeyInfo
      key_info = Nokogiri::XML::Node.new('KeyInfo', self.xml_assinado)

      # 5.1 Add X509 Data and Certificate
      x509_data = Nokogiri::XML::Node.new('X509Data', self.xml_assinado)
      x509_certificate = Nokogiri::XML::Node.new('X509Certificate', self.xml_assinado)
      x509_certificate.content = certificado.to_s.gsub(/\-\-\-\-\-[A-Z]+ CERTIFICATE\-\-\-\-\-/, "").gsub(/\n/,"")

      x509_data.add_child x509_certificate
      key_info.add_child x509_data

      # 5.2 Add KeyInfo
      signature.add_child key_info
    end

    # Return XML
    self.xml_assinado.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
  end
rescue Exception => e
  self.errors.add(:base, e.message)
ensure
  return self.errors.blank?
end
valid?() click to toggle source
# File lib/inovadora_xml/assinador.rb, line 110
def valid?
  self.errors.add(:base, "Chave não informada" )               unless self.key.present?
  self.errors.add(:base, "Certificado não informado" )         unless self.cert.present?
  self.errors.add(:base, "Arquivo chave não encontrado")       unless File.exists?(self.key.to_s)
  self.errors.add(:base, "Arquivo certificado não encontrado") unless File.exists?(self.cert.to_s)

rescue Exception => e
  self.errors.add(:base, e.message)
ensure
  return self.errors.blank?
end