Commit 747f6df

mokha <mo@mokhan.ca>
2019-01-21 18:26:12
inject custom KeyInfo
1 parent eed4a73
lib/xml/kit/templates/encryption.builder
@@ -2,11 +2,15 @@
 
 xml.EncryptedData xmlns: ::Xml::Kit::Namespaces::XMLENC do
   xml.EncryptionMethod Algorithm: symmetric_algorithm
-  xml.KeyInfo xmlns: ::Xml::Kit::Namespaces::XMLDSIG do
-    xml.EncryptedKey xmlns: ::Xml::Kit::Namespaces::XMLENC do
-      xml.EncryptionMethod Algorithm: asymmetric_algorithm
-      xml.CipherData do
-        xml.CipherValue asymmetric_cipher_value
+  if key_info
+    key_info.call(xml)
+  else
+    xml.KeyInfo xmlns: ::Xml::Kit::Namespaces::XMLDSIG do
+      xml.EncryptedKey xmlns: ::Xml::Kit::Namespaces::XMLENC do
+        xml.EncryptionMethod Algorithm: asymmetric_algorithm
+        xml.CipherData do
+          xml.CipherValue asymmetric_cipher_value
+        end
       end
     end
   end
lib/xml/kit/encryption.rb
@@ -7,12 +7,14 @@ module Xml
       attr_reader :asymmetric_cipher_value
       attr_reader :symmetric_algorithm
       attr_reader :symmetric_cipher_value
+      attr_reader :key_info
 
       def initialize(
         raw_xml,
         public_key,
         symmetric_algorithm: ::Xml::Kit::Crypto::SymmetricCipher::DEFAULT_ALGORITHM,
-        asymmetric_algorithm: ::Xml::Kit::Crypto::RsaCipher::ALGORITHM
+        asymmetric_algorithm: ::Xml::Kit::Crypto::RsaCipher::ALGORITHM,
+        key_info: nil
       )
         @symmetric_algorithm = symmetric_algorithm
         symmetric_cipher = symmetric(symmetric_algorithm)
@@ -21,6 +23,7 @@ module Xml
         @asymmetric_algorithm = asymmetric_algorithm
         asymmetric_cipher = asymmetric(asymmetric_algorithm, public_key)
         @asymmetric_cipher_value = Base64.strict_encode64(asymmetric_cipher.encrypt(symmetric_cipher.key))
+        @key_info = key_info
       end
 
       def to_xml(xml: ::Builder::XmlMarkup.new)
lib/xml/kit/templatable.rb
@@ -18,17 +18,19 @@ module Xml
       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))
+      def to_xml(xml: ::Builder::XmlMarkup.new, pretty: false)
+        result = signatures.complete(render(self, xml: xml))
+        pretty ? Nokogiri::XML(result).to_xml(indent: 2) : result
       end
 
-      def encryption_for(xml:)
+      def encryption_for(xml:, key_info: nil)
         if encrypt?
           temp = ::Builder::XmlMarkup.new
           yield temp
           ::Xml::Kit::Encryption.new(
             signatures.complete(temp.target!),
-            encryption_certificate.public_key
+            encryption_certificate.public_key,
+            key_info: key_info
           ).to_xml(xml: xml)
         else
           yield xml
spec/fixtures/item-extracted-key.builder
@@ -2,7 +2,12 @@ xml.instruct!
 xml.Item ID: id, xmlns: 'https://www.example.org/item#' do
   signature_for reference_id: id, xml: xml
   xml.Encrypted xmlns: 'https://www.example.org/item#' do
-    encryption_for xml: xml do |xml|
+    key_info = lambda do |xml|
+      xml.KeyInfo xmlns: ::Xml::Kit::Namespaces::XMLDSIG do
+        xml.RetrievalMethod xmlns: ::Xml::Kit::Namespaces::XMLDSIG, URI: "#EK", Type: "http://www.w3.org/2001/04/xmlenc#EncryptedKey"
+      end
+    end
+    encryption_for(xml: xml, key_info: key_info) do |xml|
       xml.EncryptMe do
         xml.Secret "secret"
       end
spec/xml/kit/templatable_spec.rb
@@ -97,11 +97,18 @@ RSpec.describe ::Xml::Kit::Templatable do
     specify { expect(subject.to_xml).to match_xsd('item') }
 
     context "with the key extracted to the header" do
+      let(:xml_hash) { Hash.from_xml(subject.to_xml) }
+
       before do
         subject.template_path = './spec/fixtures/item-extracted-key.builder'
       end
 
       specify { expect(subject.to_xml).to match_xsd('item-extracted-key') }
+      specify { expect(xml_hash["Item"]["Encrypted"]["EncryptedData"]["KeyInfo"]["RetrievalMethod"]).to be_present }
+      specify { expect(xml_hash["Item"]["Encrypted"]["EncryptedData"]["KeyInfo"]["RetrievalMethod"]["xmlns"]).to eql(::Xml::Kit::Namespaces::XMLDSIG) }
+      specify { expect(xml_hash["Item"]["Encrypted"]["EncryptedData"]["KeyInfo"]["RetrievalMethod"]["URI"]).to eql("#EK") }
+      specify { expect(xml_hash["Item"]["Encrypted"]["EncryptedData"]["KeyInfo"]["RetrievalMethod"]["Type"]).to eql("http://www.w3.org/2001/04/xmlenc#EncryptedKey") }
+      specify { expect(xml_hash["Item"]["Encrypted"]["EncryptedData"]["KeyInfo"]["EncryptedKey"]).to be_nil }
     end
   end
 end