# coding: utf-8 ################################################ # © Alexander Semyonov, 2011—2013, MIT License # # Author: Alexander Semyonov # ################################################ require 'xommelier' require 'base64' require 'delegate' module Xommelier module DS include Xommelier::Xml xmlns 'http://www.w3.org/2000/09/xmldsig#', as: :ds schema class CryptoBinary < DelegateClass(String) def self.from_xommelier(value) return unless value case value when %r(\A[a-zA-Z0-9+/]={0,2}\Z) new Base64.decode64(value) when String new value else new value.to_s end end def inspect %(#<#{self.class.name} "#{to_s}">) end def raw __getobj__ end def to_s to_xommelier.to_s end def to_xommelier Base64.encode64(raw) end end class Element < Xml::Element def self.find_element_name name.demodulize end # Defines containing attribute def self.attribute(name, options = {}) options[:as] ||= name.to_s.camelcase super(name, options) end def self.any!(options = {}) # TODO implement logic end def self.choice!(options = {}) # TODO implement logic may do yield end end def self.sequence!(options = {}) # TODO implement logic yield end def self.has_algorithm(map = {}) attribute :algorithm, type: Uri, required: true const_set(:ALGORITHMS, map) map.each do |name, algorithm| define_singleton_method("new_#{name}") do |options = {}| new(options.merge(algorithm: algorithm)) end end define_method(:algorithm_name) do map.key(algorithm.to_s) end end end class SignatureValue < Element attribute :id, optional: true text end class CanonicalizationMethod < Element any! ns: :any, count: :any has_algorithm( omit_comments: 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315', with_comments: 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments' ) end class SignatureMethod < Element element :hmac_output_length, as: 'HMACOutputLength', type: Integer, count: :may any! ns: :other, count: :any has_algorithm( rsa_sha1: 'http://www.w3.org/2000/09/xmldsig#rsa-sha1', dsa_sha1: 'http://www.w3.org/2000/09/xmldsig#dsa-sha1' ) end class Transform < Element choice! count: :any do any! ns: :other element :xpath, as: 'XPath' end has_algorithm( xslt: 'http://www.w3.org/TR/1999/REC-xslt-19991116', xpath: 'http://www.w3.org/TR/1999/REC-xpath-19991116', enveloped_signature: 'http://www.w3.org/2000/09/xmldsig#enveloped-signature' ) end class Transforms < Element element ref: Transform, count: :many end class DigestMethod < Element any! ns: :other, count: :any has_algorithm( sha1: 'http://www.w3.org/2000/09/xmldsig#sha1' ) end class Reference < Element element ref: Transforms, count: :may element ref: DigestMethod element :digest_value, as: 'DigestValue' attribute :id, optional: true attribute :uri, as: 'URI', type: Uri, optional: true attribute :type, type: Uri, optional: true end class SignedInfo < Element element ref: CanonicalizationMethod element ref: SignatureMethod element ref: Reference, count: :many attribute :id, optional: true end class DSAKeyValue < Element sequence! count: :may do element :p, as: 'P', type: CryptoBinary element :q, as: 'Q', type: CryptoBinary end element :g, as: 'G', type: CryptoBinary, count: :may element :y, as: 'Y', type: CryptoBinary element :j, as: 'J', type: CryptoBinary, count: :may sequence! count: :may do element :seed, as: 'Seed', type: CryptoBinary element :pgen_counter, as: 'PgenCounter', type: CryptoBinary end end class RSAKeyValue < Element sequence! do element :modulus, as: 'Modulus', type: CryptoBinary element :exponent, as: 'Exponent', type: CryptoBinary end end class KeyValue < Element choice! do element ref: DSAKeyValue element ref: RSAKeyValue any! ns: :other end end class RetrievalMethod < Element element ref: Transforms, count: :any attribute :uri, as: 'URI', type: URI attribute :type, type: URI, optional: true end class X509IssuerSerial < Element element :issuer_name, as: 'X509IssuerName' element :serial_number, as: 'X509SerialNumber', type: Integer end class X509Data < Element sequence! count: :many do choice! do element :issuer_serial, type: X509IssuerSerial element :ski, as: 'X509SKI' element :subject_name, as: 'X509SubjectName' element :certificate, as: 'X509Certificate' element :crl, as: 'X509CRL' any! ns: :other end end end class PGPData < Element element :key_id, as: 'PGPKeyID', count: :may element :key_packet, as: 'PGPKeyPacket', count: :may any! ns: :other, count: :any end class SPKIData < Element element :sexp, as: 'SPKISexp' any! ns: :other, count: :may end class KeyInfo < Element choice! count: :many do element :key_name, as: 'KeyName' element ref: KeyValue element ref: RetrievalMethod element ref: X509Data element ref: PGPData element ref: SPKIData element :mgmt_data, as: 'MgmtData' any! ns: :other end attribute :id, optional: true end class Manifest < Element element ref: Reference, count: :many attribute :id, optional: true end class SignatureProperty < Element choice! do any! ns: :other end attribute :target, type: Uri, optional: true attribute :id, optional: true end class SignatureProperties < Element element ref: SignatureProperty, count: :many attribute :id, optional: true end class Object < Element any! ns: :any, count: :any attribute :id, optional: true attribute :mime_type, optional: true attribute :encoding, type: Uri, optional: true end class Signature < Element element ref: SignedInfo element ref: SignatureValue element ref: KeyInfo, count: :may element ref: Object, count: :any attribute :id, optional: true end end end