Commit c96388a

mo <mo.khan@gmail.com>
2017-12-28 19:23:42
install xml-kit from rubygems.
1 parent 86655b6
xml-kit/bin/console
@@ -1,14 +0,0 @@
-#!/usr/bin/env ruby
-
-require "bundler/setup"
-require "xml/kit"
-
-# You can add fixtures and/or initialization code here to make experimenting
-# with your gem easier. You can also use a different console, if you like.
-
-# (If you use this, don't forget to add pry to your Gemfile!)
-# require "pry"
-# Pry.start
-
-require "irb"
-IRB.start(__FILE__)
xml-kit/bin/setup
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-IFS=$'\n\t'
-set -vx
-
-bundle install
-
-# Do any other automated setup that you need to do here
xml-kit/lib/xml/kit/builders/templates/certificate.builder
@@ -1,7 +0,0 @@
-xml.KeyDescriptor use: use do
-  xml.KeyInfo "xmlns": ::Xml::Kit::Namespaces::XMLDSIG do
-    xml.X509Data do
-      xml.X509Certificate stripped
-    end
-  end
-end
xml-kit/lib/xml/kit/builders/templates/encryption.builder
@@ -1,14 +0,0 @@
-xml.EncryptedData xmlns: ::Xml::Kit::Namespaces::XMLENC do
-  xml.EncryptionMethod Algorithm: "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
-  xml.KeyInfo xmlns: ::Xml::Kit::Namespaces::XMLDSIG do
-    xml.EncryptedKey xmlns: ::Xml::Kit::Namespaces::XMLENC do
-      xml.EncryptionMethod Algorithm: "http://www.w3.org/2001/04/xmlenc#rsa-1_5"
-      xml.CipherData do
-        xml.CipherValue Base64.encode64(public_key.public_encrypt(key))
-      end
-    end
-  end
-  xml.CipherData do
-    xml.CipherValue Base64.encode64(iv + encrypted)
-  end
-end
xml-kit/lib/xml/kit/builders/templates/nil_class.builder
xml-kit/lib/xml/kit/builders/templates/signature.builder
@@ -1,20 +0,0 @@
-xml.Signature "xmlns" => ::Xml::Kit::Namespaces::XMLDSIG do
-  xml.SignedInfo do
-    xml.CanonicalizationMethod Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#"
-    xml.SignatureMethod Algorithm: signature_method
-    xml.Reference URI: "##{reference_id}" do
-      xml.Transforms do
-        xml.Transform Algorithm: "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
-        xml.Transform Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#"
-      end
-      xml.DigestMethod Algorithm: digest_method
-      xml.DigestValue ""
-    end
-  end
-  xml.SignatureValue ""
-  xml.KeyInfo do
-    xml.X509Data do
-      xml.X509Certificate certificate.stripped
-    end
-  end
-end
xml-kit/lib/xml/kit/builders/encryption.rb
@@ -1,20 +0,0 @@
-module Xml
-  module Kit
-    module Builders
-      class Encryption
-        attr_reader :public_key
-        attr_reader :key, :iv, :encrypted
-
-        def initialize(raw_xml, public_key)
-          @public_key = public_key
-          cipher = OpenSSL::Cipher.new('AES-256-CBC')
-          cipher.encrypt
-          @key = cipher.random_key
-          @iv = cipher.random_iv
-          @encrypted = cipher.update(raw_xml) + cipher.final
-        end
-      end
-    end
-  end
-end
-
xml-kit/lib/xml/kit/builders/signature.rb
@@ -1,34 +0,0 @@
-module Xml
-  module Kit
-    module Builders
-      class Signature
-        SIGNATURE_METHODS = {
-          SHA1: "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
-          SHA224: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha224",
-          SHA256: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
-          SHA384: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
-          SHA512: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
-        }.freeze
-        DIGEST_METHODS = {
-          SHA1: "http://www.w3.org/2000/09/xmldsig#SHA1",
-          SHA224: "http://www.w3.org/2001/04/xmldsig-more#sha224",
-          SHA256: "http://www.w3.org/2001/04/xmlenc#sha256",
-          SHA384: "http://www.w3.org/2001/04/xmldsig-more#sha384",
-          SHA512: "http://www.w3.org/2001/04/xmlenc#sha512",
-        }.freeze
-
-        attr_reader :certificate
-        attr_reader :digest_method
-        attr_reader :reference_id
-        attr_reader :signature_method
-
-        def initialize(reference_id, signature_method: :SH256, digest_method: :SHA256, certificate:)
-          @certificate = certificate
-          @digest_method = DIGEST_METHODS[digest_method]
-          @reference_id = reference_id
-          @signature_method = SIGNATURE_METHODS[signature_method]
-        end
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/crypto/oaep_cipher.rb
@@ -1,22 +0,0 @@
-module Xml
-  module Kit
-    module Crypto
-      class OaepCipher
-        ALGORITHMS = {
-          'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p' => true,
-        }
-        def initialize(algorithm, key)
-          @key = key
-        end
-
-        def self.matches?(algorithm)
-          ALGORITHMS[algorithm]
-        end
-
-        def decrypt(cipher_text)
-          @key.private_decrypt(cipher_text, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
-        end
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/crypto/rsa_cipher.rb
@@ -1,23 +0,0 @@
-module Xml
-  module Kit
-    module Crypto
-      class RsaCipher
-        ALGORITHMS = {
-          'http://www.w3.org/2001/04/xmlenc#rsa-1_5' => true,
-        }
-
-        def initialize(algorithm, key)
-          @key = key
-        end
-
-        def self.matches?(algorithm)
-          ALGORITHMS[algorithm]
-        end
-
-        def decrypt(cipher_text)
-          @key.private_decrypt(cipher_text)
-        end
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/crypto/simple_cipher.rb
@@ -1,34 +0,0 @@
-module Xml
-  module Kit
-    module Crypto
-      class SimpleCipher
-        ALGORITHMS = {
-          'http://www.w3.org/2001/04/xmlenc#tripledes-cbc' => 'DES-EDE3-CBC',
-          'http://www.w3.org/2001/04/xmlenc#aes128-cbc' => 'AES-128-CBC',
-          'http://www.w3.org/2001/04/xmlenc#aes192-cbc' => 'AES-192-CBC',
-          'http://www.w3.org/2001/04/xmlenc#aes256-cbc' => 'AES-256-CBC',
-        }
-
-        def initialize(algorithm, private_key)
-          @algorithm = algorithm
-          @private_key = private_key
-        end
-
-        def self.matches?(algorithm)
-          ALGORITHMS[algorithm]
-        end
-
-        def decrypt(cipher_text)
-          cipher = OpenSSL::Cipher.new(ALGORITHMS[@algorithm])
-          cipher.decrypt
-          iv = cipher_text[0..cipher.iv_len-1]
-          data = cipher_text[cipher.iv_len..-1]
-          #cipher.padding = 0
-          cipher.key = @private_key
-          cipher.iv = iv
-          cipher.update(data) + cipher.final
-        end
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/crypto/unknown_cipher.rb
@@ -1,18 +0,0 @@
-module Xml
-  module Kit
-    module Crypto
-      class UnknownCipher
-        def initialize(algorithm, key)
-        end
-
-        def self.matches?(algorithm)
-          true
-        end
-
-        def decrypt(cipher_text)
-          cipher_text
-        end
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/certificate.rb
@@ -1,96 +0,0 @@
-module Xml
-  module Kit
-    # {include:file:spec/xml/certificate_spec.rb}
-    class Certificate
-      BEGIN_CERT=/-----BEGIN CERTIFICATE-----/
-      END_CERT=/-----END CERTIFICATE-----/
-      # The use can be `:signing` or `:encryption`
-      attr_reader :use
-
-      def initialize(value, use:)
-        @value = value
-        @use = use.downcase.to_sym
-      end
-
-      # @return [Xml::Kit::Fingerprint] the certificate fingerprint.
-      def fingerprint
-        Fingerprint.new(value)
-      end
-
-      # Returns true if this certificate is for the specified use.
-      #
-      # @param use [Symbol] `:signing` or `:encryption`.
-      # @return [Boolean] true or false.
-      def for?(use)
-        self.use == use.to_sym
-      end
-
-      # Returns true if this certificate is used for encryption.
-      #
-      # return [Boolean] true or false.
-      def encryption?
-        for?(:encryption)
-      end
-
-      # Returns true if this certificate is used for signing.
-      #
-      # return [Boolean] true or false.
-      def signing?
-        for?(:signing)
-      end
-
-      # Returns the x509 form.
-      #
-      # return [OpenSSL::X509::Certificate] the OpenSSL equivalent.
-      def x509
-        self.class.to_x509(value)
-      end
-
-      # Returns the public key.
-      #
-      # @return [OpenSSL::PKey::RSA] the RSA public key.
-      def public_key
-        x509.public_key
-      end
-
-      def ==(other)
-        self.fingerprint == other.fingerprint
-      end
-
-      def eql?(other)
-        self == other
-      end
-
-      def hash
-        value.hash
-      end
-
-      def to_s
-        value
-      end
-
-      def to_h
-        { use: @use, fingerprint: fingerprint.to_s }
-      end
-
-      def inspect
-        to_h.inspect
-      end
-
-      def stripped
-        value.to_s.gsub(BEGIN_CERT, '').gsub(END_CERT, '').gsub(/\n/, '')
-      end
-
-      def self.to_x509(value)
-        OpenSSL::X509::Certificate.new(Base64.decode64(value))
-      rescue OpenSSL::X509::CertificateError => error
-        ::Xml::Kit.logger.warn(error)
-        OpenSSL::X509::Certificate.new(value)
-      end
-
-      private
-
-      attr_reader :value
-    end
-  end
-end
xml-kit/lib/xml/kit/crypto.rb
@@ -1,17 +0,0 @@
-require 'xml/kit/crypto/oaep_cipher'
-require 'xml/kit/crypto/rsa_cipher'
-require 'xml/kit/crypto/simple_cipher'
-require 'xml/kit/crypto/unknown_cipher'
-
-module Xml
-  module Kit
-    module Crypto
-      DECRYPTORS = [ SimpleCipher, RsaCipher, OaepCipher, UnknownCipher ]
-
-      # @!visibility private
-      def self.decryptor_for(algorithm, key)
-        DECRYPTORS.find { |x| x.matches?(algorithm) }.new(algorithm, key)
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/decryption.rb
@@ -1,44 +0,0 @@
-module Xml
-  module Kit
-    # {include:file:spec/saml/xml_decryption_spec.rb}
-    class Decryption
-      # The list of private keys to use to attempt to decrypt the document.
-      attr_reader :private_keys
-
-      def initialize(private_keys:)
-        @private_keys = private_keys
-      end
-
-      # Decrypts an EncryptedData section of an XML document.
-      #
-      # @param data [Hash] the XML document converted to a [Hash] using Hash.from_xml.
-      def decrypt(data)
-        encrypted_data = data['EncryptedData']
-        symmetric_key = symmetric_key_from(encrypted_data)
-        cipher_text = Base64.decode64(encrypted_data["CipherData"]["CipherValue"])
-        to_plaintext(cipher_text, symmetric_key, encrypted_data["EncryptionMethod"]['Algorithm'])
-      end
-
-      private
-
-      def symmetric_key_from(encrypted_data)
-        encrypted_key = encrypted_data['KeyInfo']['EncryptedKey']
-        cipher_text = Base64.decode64(encrypted_key['CipherData']['CipherValue'])
-        attempts = private_keys.count
-        private_keys.each do |private_key|
-          begin
-            attempts -= 1
-            return to_plaintext(cipher_text, private_key, encrypted_key["EncryptionMethod"]['Algorithm'])
-          rescue OpenSSL::PKey::RSAError => error
-            ::Xml::Kit.logger.error(error)
-            raise if attempts.zero?
-          end
-        end
-      end
-
-      def to_plaintext(cipher_text, symmetric_key, algorithm)
-        Crypto.decryptor_for(algorithm, symmetric_key).decrypt(cipher_text)
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/document.rb
@@ -1,75 +0,0 @@
-module Xml
-  module Kit
-    # {include:file:spec/saml/xml_spec.rb}
-    class Document
-      include ActiveModel::Validations
-      NAMESPACES = { "ds": ::Xml::Kit::Namespaces::XMLDSIG }.freeze
-
-      validate :validate_signatures
-      validate :validate_certificates
-
-      def initialize(raw_xml, namespaces: NAMESPACES)
-        @raw_xml = raw_xml
-        @namespaces = namespaces
-        @document = ::Nokogiri::XML(raw_xml)
-      end
-
-      # Returns the first XML node found by searching the document with the provided XPath.
-      #
-      # @param xpath [String] the XPath to use to search the document
-      def find_by(xpath)
-        document.at_xpath(xpath, namespaces)
-      end
-
-      # Returns all XML nodes found by searching the document with the provided XPath.
-      #
-      # @param xpath [String] the XPath to use to search the document
-      def find_all(xpath)
-        document.search(xpath, namespaces)
-      end
-
-      # Return the XML document as a [String].
-      #
-      # @param pretty [Boolean] return the XML string in a human readable format if true.
-      def to_xml(pretty: true)
-        pretty ? document.to_xml(indent: 2) : raw_xml
-      end
-
-      private
-
-      attr_reader :raw_xml, :document, :namespaces
-
-      def validate_signatures
-        invalid_signatures.flat_map(&:errors).uniq.each do |error|
-          errors.add(error, "is invalid")
-        end
-      end
-
-      def invalid_signatures
-        signed_document = Xmldsig::SignedDocument.new(document, id_attr: 'ID=$uri or @Id')
-        signed_document.signatures.find_all do |signature|
-          x509_certificates.all? do |certificate|
-            !signature.valid?(certificate)
-          end
-        end
-      end
-
-      def validate_certificates(now = Time.current)
-        return if find_by('//ds:Signature').nil?
-
-        x509_certificates.each do |certificate|
-          inactive = now < certificate.not_before
-          errors.add(:certificate, "Not valid before #{certificate.not_before}") if inactive
-
-          expired = now > certificate.not_after
-          errors.add(:certificate, "Not valid after #{certificate.not_after}") if expired
-        end
-      end
-
-      def x509_certificates
-        xpath = "//ds:KeyInfo/ds:X509Data/ds:X509Certificate"
-        find_all(xpath).map { |item| Certificate.to_x509(item.text) }
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/fingerprint.rb
@@ -1,50 +0,0 @@
-module Xml
-  module Kit
-    # This generates a fingerprint for an X509 Certificate.
-    #
-    #   certificate, _ = Xml::Kit::SelfSignedCertificate.new("password").create
-    #
-    #   puts Xml::Kit::Fingerprint.new(certificate).to_s
-    #   # B7:AB:DC:BD:4D:23:58:65:FD:1A:99:0C:5F:89:EA:87:AD:F1:D7:83:34:7A:E9:E4:88:12:DD:46:1F:38:05:93
-    #
-    # {include:file:spec/saml/fingerprint_spec.rb}
-    class Fingerprint
-      # The OpenSSL::X509::Certificate
-      attr_reader :x509
-
-      def initialize(raw_certificate)
-        @x509 = Certificate.to_x509(raw_certificate)
-      end
-
-      # Generates a formatted fingerprint using the specified hash algorithm.
-      #
-      # @param algorithm [OpenSSL::Digest] the openssl algorithm to use `OpenSSL::Digest::SHA256`, `OpenSSL::Digest::SHA1`.
-      # @return [String] in the format of `"BF:ED:C5:F1:6C:AB:F5:B2:15:1F:BF:BD:7D:68:1A:F9:A5:4E:4C:19:30:BC:6D:25:B1:8E:98:D4:23:FD:B4:09"`
-      def algorithm(algorithm)
-        pretty_fingerprint(algorithm.new.hexdigest(x509.to_der))
-      end
-
-      def ==(other)
-        self.to_s == other.to_s
-      end
-
-      def eql?(other)
-        self == other
-      end
-
-      def hash
-        to_s.hash
-      end
-
-      def to_s
-        algorithm(OpenSSL::Digest::SHA256)
-      end
-
-      private
-
-      def pretty_fingerprint(fingerprint)
-        fingerprint.upcase.scan(/../).join(":")
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/id.rb
@@ -1,13 +0,0 @@
-module Xml
-  module Kit
-    # This class is used primary for generating ID.
-    #https://www.w3.org/2001/XMLSchema.xsd
-    class Id
-      # Generate an ID that conforms to the XML Schema.
-      # https://www.w3.org/2001/XMLSchema.xsd
-      def self.generate
-        "_#{SecureRandom.uuid}"
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/key_pair.rb
@@ -1,29 +0,0 @@
-module Xml
-  module Kit
-    class KeyPair # :nodoc:
-      attr_reader :certificate, :private_key, :use
-
-      def initialize(certificate, private_key, passphrase, use)
-        @use = use
-        @certificate = ::Xml::Kit::Certificate.new(certificate, use: use)
-        @private_key = OpenSSL::PKey::RSA.new(private_key, passphrase)
-      end
-
-      # Returns true if the key pair is the designated use.
-      #
-      # @param use [Symbol] Can be either `:signing` or `:encryption`.
-      def for?(use)
-        @use == use
-      end
-
-      # Returns a generated self signed certificate with private key.
-      #
-      # @param use [Symbol] Can be either `:signing` or `:encryption`.
-      # @param passphrase [String] the passphrase to use to encrypt the private key.
-      def self.generate(use:, passphrase: SecureRandom.uuid)
-        certificate, private_key = ::Xml::Kit::SelfSignedCertificate.new(passphrase).create
-        new(certificate, private_key, passphrase, use)
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/namespaces.rb
@@ -1,17 +0,0 @@
-module Xml
-  module Kit
-    module Namespaces
-      ENVELOPED_SIG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
-      RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
-      RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
-      RSA_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"
-      RSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
-      SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1"
-      SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256'
-      SHA384 = "http://www.w3.org/2001/04/xmldsig-more#sha384"
-      SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512'
-      XMLDSIG = "http://www.w3.org/2000/09/xmldsig#"
-      XMLENC = "http://www.w3.org/2001/04/xmlenc#"
-    end
-  end
-end
xml-kit/lib/xml/kit/self_signed_certificate.rb
@@ -1,28 +0,0 @@
-module Xml
-  module Kit
-    class SelfSignedCertificate
-      SUBJECT="/C=CA/ST=Alberta/L=Calgary/O=XmlKit/OU=XmlKit/CN=XmlKit"
-
-      def initialize(passphrase)
-        @passphrase = passphrase
-      end
-
-      def create
-        rsa_key = OpenSSL::PKey::RSA.new(2048)
-        public_key = rsa_key.public_key
-        certificate = OpenSSL::X509::Certificate.new
-        certificate.subject = certificate.issuer = OpenSSL::X509::Name.parse(SUBJECT)
-        certificate.not_before = Time.now.to_i
-        certificate.not_after = (Date.today + 30).to_time.to_i
-        certificate.public_key = public_key
-        certificate.serial = 0x0
-        certificate.version = 2
-        certificate.sign(rsa_key, OpenSSL::Digest::SHA256.new)
-        [
-          certificate.to_pem,
-          rsa_key.to_pem(OpenSSL::Cipher.new('AES-256-CBC'), @passphrase)
-        ]
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/signatures.rb
@@ -1,67 +0,0 @@
-module Xml
-  module Kit
-    # @!visibility private
-    class Signatures # :nodoc:
-      attr_reader :key_pair, :signature_method, :digest_method
-
-      # @!visibility private
-      def initialize(key_pair:, signature_method:, digest_method:)
-        @digest_method = digest_method
-        @key_pair = key_pair
-        @signature_method = signature_method
-      end
-
-      # @!visibility private
-      def sign_with(key_pair)
-        @key_pair = key_pair
-      end
-
-      # @!visibility private
-      def build(reference_id)
-        return nil if key_pair.nil?
-
-        ::Xml::Kit::Builders::Signature.new(
-          reference_id,
-          certificate: key_pair.certificate,
-          signature_method: signature_method,
-          digest_method: digest_method
-        )
-      end
-
-      # @!visibility private
-      def complete(raw_xml)
-        return raw_xml if key_pair.nil?
-
-        private_key = key_pair.private_key
-        Xmldsig::SignedDocument.new(raw_xml).sign(private_key)
-      end
-
-      # @!visibility private
-      def self.sign(xml: ::Builder::XmlMarkup.new, key_pair:, signature_method: :SHA256, digest_method: :SHA256)
-        signatures = new(
-          key_pair: key_pair,
-          signature_method: signature_method,
-          digest_method: digest_method,
-        )
-        yield xml, XmlSignatureTemplate.new(xml, signatures)
-        signatures.complete(xml.target!)
-      end
-
-      class XmlSignatureTemplate # :nodoc:
-        # @!visibility private
-        attr_reader :signatures, :xml
-
-        # @!visibility private
-        def initialize(xml, signatures)
-          @signatures = signatures
-          @xml = xml
-        end
-
-        # @!visibility private
-        def template(reference_id)
-          Template.new(signatures.build(reference_id)).to_xml(xml: xml)
-        end
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/templatable.rb
@@ -1,83 +0,0 @@
-module Xml
-  module Kit
-    module Templatable
-      # Can be used to disable embeding a signature.
-      # By default a signature will be embedded if a signing
-      # certificate is available.
-      attr_accessor :embed_signature
-
-      # Used to enable/disable encrypting the document.
-      attr_accessor :encrypt
-
-      # The [Xml::Kit::KeyPair] to use for generating a signature.
-      attr_accessor :signing_key_pair
-
-      # The [Xml::Kit::Certificate] that contains the public key to use for encrypting the document.
-      attr_accessor :encryption_certificate
-
-      # Returns the generated XML document with an XML Digital Signature and XML Encryption.
-      def to_xml(xml: ::Builder::XmlMarkup.new)
-        signatures.complete(render(self, xml: xml))
-      end
-
-      def encryption_for(xml:)
-        if encrypt?
-          temp = ::Builder::XmlMarkup.new
-          yield temp
-          signed_xml = signatures.complete(temp.target!)
-          xml_encryption = ::Xml::Kit::Builders::Encryption.new(
-            signed_xml,
-            encryption_certificate.public_key
-          )
-          render(xml_encryption, xml: xml)
-        else
-          yield xml
-        end
-      end
-
-      def render(model, options)
-        ::Xml::Kit::Template.new(model).to_xml(options)
-      end
-
-      def signature_for(reference_id:, xml:)
-        return unless sign?
-        render(signatures.build(reference_id), xml: xml)
-      end
-
-      # Allows you to specify which key pair to use for generating an XML digital signature.
-      #
-      # @param key_pair [Xml::Kit::KeyPair] the key pair to use for signing.
-      def sign_with(key_pair)
-        signatures.sign_with(key_pair)
-      end
-
-      private
-
-      def sign?
-        embed_signature
-      end
-
-      # @!visibility private
-      def signatures
-        @signatures ||= ::Xml::Kit::Signatures.new(
-          key_pair: signing_key_pair,
-          digest_method: digest_method,
-          signature_method: signature_method,
-        )
-      end
-
-      def digest_method
-        :SHA256
-      end
-
-      def signature_method
-        :SHA256
-      end
-
-      # @!visibility private
-      def encrypt?
-        encrypt && encryption_certificate
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/template.rb
@@ -1,32 +0,0 @@
-module Xml
-  module Kit
-    class Template
-      attr_reader :target
-
-      def initialize(target)
-        @target = target
-      end
-
-      # Returns the compiled template as a [String].
-      #
-      # @param options [Hash] The options hash to pass to the template engine.
-      def to_xml(options = {})
-        template.render(target, options)
-      end
-
-      private
-
-      def template_path
-        return target.template_path if target.respond_to?(:template_path)
-
-        root_path = File.expand_path(File.dirname(__FILE__))
-        template_name = "#{target.class.name.split("::").last.underscore}.builder"
-        File.join(root_path, "builders/templates/", template_name)
-      end
-
-      def template
-        Tilt.new(template_path)
-      end
-    end
-  end
-end
xml-kit/lib/xml/kit/version.rb
@@ -1,5 +0,0 @@
-module Xml
-  module Kit
-    VERSION = "0.1.0"
-  end
-end
xml-kit/lib/xml/kit.rb
@@ -1,40 +0,0 @@
-require "active_model"
-require "active_support/core_ext/numeric/time"
-require "base64"
-require "builder"
-require "logger"
-require "nokogiri"
-require "openssl"
-require "tilt"
-require "xmldsig"
-
-require "xml/kit/namespaces"
-
-require "xml/kit/builders/encryption"
-require "xml/kit/builders/signature"
-require "xml/kit/certificate"
-require "xml/kit/crypto"
-require "xml/kit/decryption"
-require "xml/kit/document"
-require "xml/kit/fingerprint"
-require "xml/kit/id"
-require "xml/kit/key_pair"
-require "xml/kit/self_signed_certificate"
-require "xml/kit/signatures"
-require "xml/kit/templatable"
-require "xml/kit/template"
-require "xml/kit/version"
-
-module Xml
-  module Kit
-    class << self
-      def logger
-        @logger ||= Logger.new(STDOUT)
-      end
-
-      def logger=(logger)
-        @logger = logger
-      end
-    end
-  end
-end
xml-kit/spec/fixtures/item.builder
@@ -1,4 +0,0 @@
-xml.instruct!
-xml.Item ID: id do
-  signature_for(reference_id: id, xml: xml)
-end
xml-kit/spec/support/certificate_helper.rb
@@ -1,5 +0,0 @@
-module CertificateHelper
-  def generate_key_pair(passphrase)
-    ::Xml::Kit::SelfSignedCertificate.new(passphrase).create
-  end
-end
xml-kit/spec/xml/certificate_spec.rb
@@ -1,10 +0,0 @@
-RSpec.describe Xml::Kit::Certificate do
-  subject { described_class.new(certificate, use: :signing) }
-  let(:certificate) { generate_key_pair('password')[0] }
-
-  describe "#fingerprint" do
-    it 'returns a fingerprint' do
-      expect(subject.fingerprint).to be_instance_of(Xml::Kit::Fingerprint)
-    end
-  end
-end
xml-kit/spec/xml/decryption_spec.rb
@@ -1,134 +0,0 @@
-RSpec.describe Xml::Kit::Decryption do
-  describe "#decrypt" do
-    let(:secret) { FFaker::Movie.title }
-    let(:password) { FFaker::Movie.title }
-
-    it 'decrypts the data' do
-      certificate_pem, private_key_pem = generate_key_pair(password)
-
-      public_key = OpenSSL::X509::Certificate.new(certificate_pem).public_key
-      private_key = OpenSSL::PKey::RSA.new(private_key_pem, password)
-
-      cipher = OpenSSL::Cipher.new('AES-128-CBC')
-      cipher.encrypt
-      key = cipher.random_key
-      iv = cipher.random_iv
-      encrypted = cipher.update(secret) + cipher.final
-
-      data = {
-        "EncryptedData"=> {
-          "xmlns:xenc"=>"http://www.w3.org/2001/04/xmlenc#",
-          "xmlns:dsig"=>"http://www.w3.org/2000/09/xmldsig#",
-          "Type"=>"http://www.w3.org/2001/04/xmlenc#Element",
-          "EncryptionMethod"=> {
-            "Algorithm"=>"http://www.w3.org/2001/04/xmlenc#aes128-cbc"
-          },
-          "KeyInfo"=> {
-            "xmlns:dsig"=>"http://www.w3.org/2000/09/xmldsig#",
-            "EncryptedKey"=> {
-              "EncryptionMethod"=>{
-                "Algorithm"=>"http://www.w3.org/2001/04/xmlenc#rsa-1_5"
-              },
-              "CipherData"=>{
-                "CipherValue"=> Base64.encode64(public_key.public_encrypt(key))
-              }
-            }
-          },
-          "CipherData"=>{
-            "CipherValue"=> Base64.encode64(iv + encrypted)
-          }
-        }
-      }
-      subject = described_class.new(private_keys: [private_key])
-      decrypted = subject.decrypt(data)
-      expect(decrypted.strip).to eql(secret)
-    end
-
-    it 'attemps to decrypt with each encryption keypair' do
-      certificate_pem, private_key_pem = generate_key_pair(password)
-      public_key = OpenSSL::X509::Certificate.new(certificate_pem).public_key
-      private_key = OpenSSL::PKey::RSA.new(private_key_pem, password)
-
-      cipher = OpenSSL::Cipher.new('AES-128-CBC')
-      cipher.encrypt
-      key = cipher.random_key
-      iv = cipher.random_iv
-      encrypted = cipher.update(secret) + cipher.final
-
-      data = {
-        "EncryptedData"=> {
-          "xmlns:xenc"=>"http://www.w3.org/2001/04/xmlenc#",
-          "xmlns:dsig"=>"http://www.w3.org/2000/09/xmldsig#",
-          "Type"=>"http://www.w3.org/2001/04/xmlenc#Element",
-          "EncryptionMethod"=> {
-            "Algorithm"=>"http://www.w3.org/2001/04/xmlenc#aes128-cbc"
-          },
-          "KeyInfo"=> {
-            "xmlns:dsig"=>"http://www.w3.org/2000/09/xmldsig#",
-            "EncryptedKey"=> {
-              "EncryptionMethod"=>{
-                "Algorithm"=>"http://www.w3.org/2001/04/xmlenc#rsa-1_5"
-              },
-              "CipherData"=>{
-                "CipherValue"=> Base64.encode64(public_key.public_encrypt(key))
-              }
-            }
-          },
-          "CipherData"=>{
-            "CipherValue"=> Base64.encode64(iv + encrypted)
-          }
-        }
-      }
-
-      _, other_private_key_pem = generate_key_pair(password)
-      other_private_key = OpenSSL::PKey::RSA.new(other_private_key_pem, password)
-
-      subject = described_class.new(private_keys: [other_private_key, private_key])
-      decrypted = subject.decrypt(data)
-      expect(decrypted.strip).to eql(secret)
-    end
-
-    it 'raise an error when it cannot decrypt the data' do
-      certificate_pem, _ = generate_key_pair(password)
-      public_key = OpenSSL::X509::Certificate.new(certificate_pem).public_key
-
-      cipher = OpenSSL::Cipher.new('AES-128-CBC')
-      cipher.encrypt
-      key = cipher.random_key
-      iv = cipher.random_iv
-      encrypted = cipher.update(secret) + cipher.final
-
-      data = {
-        "EncryptedData"=> {
-          "xmlns:xenc"=>"http://www.w3.org/2001/04/xmlenc#",
-          "xmlns:dsig"=>"http://www.w3.org/2000/09/xmldsig#",
-          "Type"=>"http://www.w3.org/2001/04/xmlenc#Element",
-          "EncryptionMethod"=> {
-            "Algorithm"=>"http://www.w3.org/2001/04/xmlenc#aes128-cbc"
-          },
-          "KeyInfo"=> {
-            "xmlns:dsig"=>"http://www.w3.org/2000/09/xmldsig#",
-            "EncryptedKey"=> {
-              "EncryptionMethod"=>{
-                "Algorithm"=>"http://www.w3.org/2001/04/xmlenc#rsa-1_5"
-              },
-              "CipherData"=>{
-                "CipherValue"=> Base64.encode64(public_key.public_encrypt(key))
-              }
-            }
-          },
-          "CipherData"=>{
-            "CipherValue"=> Base64.encode64(iv + encrypted)
-          }
-        }
-      }
-
-      new_private_key_pem = generate_key_pair(password)[1]
-      new_private_key = OpenSSL::PKey::RSA.new(new_private_key_pem, password)
-      subject = described_class.new(private_keys: [new_private_key])
-      expect do
-        subject.decrypt(data)
-      end.to raise_error(OpenSSL::PKey::RSAError)
-    end
-  end
-end
xml-kit/spec/xml/document_spec.rb
@@ -1,50 +0,0 @@
-RSpec.describe Xml::Kit::Document do
-  class Item
-    include ::Xml::Kit::Templatable
-
-    attr_reader :id, :signing_key_pair
-
-    def initialize
-      @id = ::Xml::Kit::Id.generate
-      @signing_key_pair = ::Xml::Kit::KeyPair.generate(use: :signing)
-      @embed_signature = true
-    end
-
-    def template_path
-      current_path = File.expand_path(File.dirname(__FILE__))
-      File.join(current_path, "../fixtures/item.builder")
-    end
-  end
-
-  describe "#valid_signature?" do
-    let(:login_url) { "https://#{FFaker::Internet.domain_name}/login" }
-    let(:logout_url) { "https://#{FFaker::Internet.domain_name}/logout" }
-    let(:signed_xml) { Item.new.to_xml }
-
-    it 'returns true, when the digest and signature is valid' do
-      expect(described_class.new(signed_xml)).to be_valid
-    end
-
-    it 'returns false, when the SHA1 digest is not valid' do
-      subject = described_class.new(signed_xml.gsub("Item", "uhoh"))
-      expect(subject).to_not be_valid
-      expect(subject.errors[:digest_value]).to be_present
-    end
-
-    it 'it is invalid when digest is incorrect' do
-      old_digest = Hash.from_xml(signed_xml)['Item']['Signature']['SignedInfo']['Reference']['DigestValue']
-
-      subject = described_class.new(signed_xml.gsub(old_digest, 'sabotage'))
-      expect(subject).to_not be_valid
-      expect(subject.errors[:digest_value]).to be_present
-    end
-
-    it 'returns false, when the signature is invalid' do
-      old_signature = Hash.from_xml(signed_xml)['Item']['Signature']['SignatureValue']
-      signed_xml.gsub!(old_signature, 'sabotage')
-      subject = described_class.new(signed_xml)
-      expect(subject).to_not be_valid
-      expect(subject.errors[:signature]).to be_present
-    end
-  end
-end
xml-kit/spec/xml/fingerprint_spec.rb
@@ -1,27 +0,0 @@
-RSpec.describe Xml::Kit::Fingerprint do
-  describe "#sha" do
-    it 'returns the SHA256' do
-      certificate, _ = generate_key_pair("password")
-      x509 = OpenSSL::X509::Certificate.new(certificate)
-      sha256 = OpenSSL::Digest::SHA256.new.hexdigest(x509.to_der).upcase.scan(/../).join(":")
-
-      expect(described_class.new(certificate).algorithm(OpenSSL::Digest::SHA256)).to eql(sha256)
-    end
-
-    it 'returns the SHA1' do
-      certificate, _ = generate_key_pair("password")
-      x509 = OpenSSL::X509::Certificate.new(certificate)
-      sha1 = OpenSSL::Digest::SHA1.new.hexdigest(x509.to_der).upcase.scan(/../).join(":")
-
-      expect(described_class.new(certificate).algorithm(OpenSSL::Digest::SHA1)).to eql(sha1)
-    end
-  end
-
-  it 'produces correct hash keys' do
-    certificate, _ = generate_key_pair("password")
-    items = { }
-    items[described_class.new(certificate)] = "HI"
-    items[described_class.new(certificate)] = "BYE"
-    expect(items.keys.count).to eql(1)
-  end
-end
xml-kit/spec/xml/kit_spec.rb
@@ -1,5 +0,0 @@
-RSpec.describe Xml::Kit do
-  it "has a version number" do
-    expect(Xml::Kit::VERSION).not_to be nil
-  end
-end
xml-kit/spec/xml/signatures_spec.rb
@@ -1,48 +0,0 @@
-RSpec.describe ::Xml::Kit::Signatures do
-  let(:reference_id) { Xml::Kit::Id.generate }
-
-  it 'generates a signature' do
-    options = {
-      "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol",
-      "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion",
-      ID: reference_id,
-    }
-    key_pair = ::Xml::Kit::KeyPair.generate(use: :signing)
-    signed_xml = described_class.sign(key_pair: key_pair) do |xml, signature|
-      xml.tag!('samlp:AuthnRequest', options) do
-        signature.template(reference_id)
-        xml.tag!('saml:Issuer', "MyEntityID")
-      end
-    end
-    result = Hash.from_xml(signed_xml)
-
-    signature = result["AuthnRequest"]["Signature"]
-    expect(signature['xmlns']).to eql("http://www.w3.org/2000/09/xmldsig#")
-    expect(signature['SignedInfo']['CanonicalizationMethod']['Algorithm']).to eql('http://www.w3.org/2001/10/xml-exc-c14n#')
-    expect(signature['SignedInfo']['SignatureMethod']['Algorithm']).to eql("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")
-
-    expect(signature['SignedInfo']['Reference']['URI']).to eql("##{reference_id}")
-    expect(signature['SignedInfo']['Reference']['Transforms']['Transform']).to match_array([
-      { "Algorithm" => "http://www.w3.org/2000/09/xmldsig#enveloped-signature" },
-      { "Algorithm" => "http://www.w3.org/2001/10/xml-exc-c14n#" }
-    ])
-    expect(signature['SignedInfo']['Reference']['DigestMethod']['Algorithm']).to eql("http://www.w3.org/2001/04/xmlenc#sha256")
-    expected_certificate = key_pair.certificate.stripped
-    expect(signature['KeyInfo']['X509Data']['X509Certificate']).to eql(expected_certificate)
-    expect(signature['SignedInfo']['Reference']['DigestValue']).to be_present
-    expect(signature['SignatureValue']).to be_present
-    expect(OpenSSL::X509::Certificate.new(Base64.decode64(signature['KeyInfo']['X509Data']['X509Certificate']))).to be_present
-  end
-
-  it 'does not add a signature' do
-    signed_xml = described_class.sign(key_pair: nil) do |xml, signature|
-      xml.AuthnRequest do
-        signature.template(reference_id)
-        xml.Issuer "MyEntityID"
-      end
-    end
-    result = Hash.from_xml(signed_xml)
-    expect(result['AuthnRequest']).to be_present
-    expect(result["AuthnRequest"]["Signature"]).to be_nil
-  end
-end
xml-kit/spec/spec_helper.rb
@@ -1,20 +0,0 @@
-require "bundler/setup"
-require "xml/kit"
-require "ffaker"
-require "active_support/core_ext/hash/conversions"
-
-Xml::Kit.logger.level = Logger::FATAL
-
-Dir[File.join(Dir.pwd, 'spec/support/**/*.rb')].each { |f| require f }
-RSpec.configure do |config|
-  # Enable flags like --only-failures and --next-failure
-  config.example_status_persistence_file_path = ".rspec_status"
-
-  # Disable RSpec exposing methods globally on `Module` and `main`
-  config.disable_monkey_patching!
-
-  config.expect_with :rspec do |c|
-    c.syntax = :expect
-  end
-  config.include CertificateHelper
-end
xml-kit/.gitignore
@@ -1,11 +0,0 @@
-/.bundle/
-/.yardoc
-/_yardoc/
-/coverage/
-/doc/
-/pkg/
-/spec/reports/
-/tmp/
-
-# rspec failure tracking
-.rspec_status
xml-kit/.rspec
@@ -1,3 +0,0 @@
---format documentation
---color
---require spec_helper
xml-kit/.travis.yml
@@ -1,5 +0,0 @@
-sudo: false
-language: ruby
-rvm:
-  - 2.4.3
-before_install: gem install bundler -v 1.16.0
xml-kit/Gemfile
@@ -1,6 +0,0 @@
-source "https://rubygems.org"
-
-git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
-
-# Specify your gem's dependencies in xml-kit.gemspec
-gemspec
xml-kit/LICENSE.txt
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2017 mo
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
xml-kit/Rakefile
@@ -1,6 +0,0 @@
-require "bundler/gem_tasks"
-require "rspec/core/rake_task"
-
-RSpec::Core::RakeTask.new(:spec)
-
-task :default => :spec
xml-kit/README.md
@@ -1,39 +0,0 @@
-# Xml::Kit
-
-Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/xml/kit`. To experiment with that code, run `bin/console` for an interactive prompt.
-
-TODO: Delete this and the text above, and describe your gem
-
-## Installation
-
-Add this line to your application's Gemfile:
-
-```ruby
-gem 'xml-kit'
-```
-
-And then execute:
-
-    $ bundle
-
-Or install it yourself as:
-
-    $ gem install xml-kit
-
-## Usage
-
-TODO: Write usage instructions here
-
-## Development
-
-After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
-
-To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
-
-## Contributing
-
-Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/xml-kit.
-
-## License
-
-The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
xml-kit/xml-kit.gemspec
@@ -1,35 +0,0 @@
-# coding: utf-8
-lib = File.expand_path("../lib", __FILE__)
-$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
-require "xml/kit/version"
-
-Gem::Specification.new do |spec|
-  spec.name          = "xml-kit"
-  spec.version       = Xml::Kit::VERSION
-  spec.authors       = ["mo khan"]
-  spec.email         = ["mo@mokhan.ca"]
-
-  spec.summary       = %q{A simple toolkit for working with XML.}
-  spec.description   = %q{A simple toolkit for working with XML.}
-  spec.homepage      = "http://www.mokhan.ca"
-  spec.license       = "MIT"
-  spec.required_ruby_version = '>= 2.2.0'
-
-  spec.files         = `git ls-files -z`.split("\x0").reject do |f|
-    f.match(%r{^(test|spec|features)/})
-  end
-  spec.metadata["yard.run"] = "yri"
-  spec.bindir        = "exe"
-  spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
-  spec.require_paths = ["lib"]
-
-  spec.add_dependency "activemodel", ">= 4.2.0"
-  spec.add_dependency "builder", "~> 3.2"
-  spec.add_dependency "nokogiri", "~> 1.8"
-  spec.add_dependency "tilt", "~> 2.0"
-  spec.add_dependency "xmldsig", "~> 0.6"
-  spec.add_development_dependency "bundler", "~> 1.16"
-  spec.add_development_dependency "ffaker", "~> 2.7"
-  spec.add_development_dependency "rake", "~> 10.0"
-  spec.add_development_dependency "rspec", "~> 3.0"
-end
Gemfile
@@ -4,5 +4,3 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
 
 # Specify your gem's dependencies in saml-kit.gemspec
 gemspec
-
-gem 'xml-kit', path: 'xml-kit'