main
 1# frozen_string_literal: true
 2
 3require 'xml/kit/key_info/key_value'
 4require 'xml/kit/key_info/retrieval_method'
 5require 'xml/kit/key_info/rsa_key_value'
 6
 7module Xml
 8  module Kit
 9    # An implementation of the KeyInfo element.
10    # https://www.w3.org/TR/xmldsig-core1/#sec-KeyInfo
11    #
12    # @since 0.3.0
13    class KeyInfo
14      include Templatable
15      attr_accessor :key_name
16      attr_accessor :x509_data
17      attr_accessor :encrypted_key
18
19      def initialize(x509: nil, encrypted_key: nil)
20        @encrypted_key = encrypted_key
21        @x509_data = x509
22        yield self if block_given?
23      end
24
25      def asymmetric_cipher(algorithm: Crypto::RsaCipher::ALGORITHM)
26        return encrypted_key.asymmetric_cipher if encrypted_key
27
28        if x509_data
29          return Crypto.cipher_for(
30            derive_algorithm_from(x509_data.public_key),
31            x509_data.public_key
32          )
33        end
34
35        super(algorithm: algorithm)
36      end
37
38      def symmetric_cipher
39        return super if encrypted_key.nil?
40
41        encrypted_key.symmetric_cipher
42      end
43
44      def key_value
45        @key_value ||= KeyValue.new
46      end
47
48      def retrieval_method
49        @retrieval_method ||= RetrievalMethod.new
50      end
51
52      def subject_key_identifier
53        ski = x509_data.extensions.find { |x| x.oid == 'subjectKeyIdentifier' }
54        return if ski.nil?
55
56        Base64.strict_encode64(ski.value)
57      end
58
59      private
60
61      def derive_algorithm_from(key)
62        case key
63        when OpenSSL::PKey::RSA
64          "#{::Xml::Kit::Namespaces::XMLENC}rsa-1_5"
65        else
66          raise ::Xml::Kit::Error, "#{key.try(:class)} is not supported"
67        end
68      end
69    end
70  end
71end