lib/yoti/util/anchor_processor.rb in yoti-1.4.0 vs lib/yoti/util/anchor_processor.rb in yoti-1.5.0

- old
+ new

@@ -1,61 +1,98 @@ require 'openssl' require 'date' module Yoti + # # Parse attribute anchors + # class AnchorProcessor + # + # @param [Array<Yoti::Protobuf::Attrpubapi::Anchor>] + # def initialize(anchors_list) @anchors_list = anchors_list @get_next = false end + # + # Extract matching Attribute Anchors from list. + # + # @return [Array<Yoti::Anchor>] + # def process - result_data = { 'sources' => [], 'verifiers' => [] } - anchor_types = self.anchor_types + result_data = ANCHOR_LIST_KEYS.map { |key, _value| [key, []] }.to_h @anchors_list.each do |anchor| x509_certs_list = convert_certs_list_to_X509(anchor.origin_server_certs) - yoti_signed_time_stamp = process_signed_time_stamp(anchor.signed_time_stamp) - - anchor.origin_server_certs.each do |cert| - anchor_types.each do |type, oid| - yoti_anchor = get_anchor_by_oid(cert, oid, anchor.sub_type, yoti_signed_time_stamp, x509_certs_list) - result_data[type].push(yoti_anchor) unless yoti_anchor.nil? - end - end + signed_time_stamp = process_signed_time_stamp(anchor.signed_time_stamp) + yoti_anchor = get_anchor_from_certs(x509_certs_list, anchor.sub_type, signed_time_stamp) + anchor_list_key = get_anchor_list_key_by_type(yoti_anchor.type) + result_data[anchor_list_key].push(yoti_anchor) end result_data end + # + # Convert certificate list to a list of X509 certificates. + # + # @param [Google::Protobuf::RepeatedField] certs_list + # + # @return [Array<OpenSSL::X509::Certificate>] + # def convert_certs_list_to_X509(certs_list) x509_certs_list = [] certs_list.each do |cert| - x509_cert = OpenSSL::X509::Certificate.new cert - x509_certs_list.push x509_cert + x509_certs_list.push OpenSSL::X509::Certificate.new(cert) end - x509_certs_list end + # + # Return signed timestamp. + # + # @param [String] signed_time_stamp_binary + # + # @return [Yoti::SignedTimeStamp] + # def process_signed_time_stamp(signed_time_stamp_binary) signed_time_stamp = Yoti::Protobuf::Compubapi::SignedTimestamp.decode(signed_time_stamp_binary) - time_in_sec = signed_time_stamp.timestamp / 1000000 - date_time = Time.parse(Time.at(time_in_sec).to_s) - Yoti::SignedTimeStamp.new(signed_time_stamp.version, date_time) + time_in_sec = signed_time_stamp.timestamp.quo(1000000) + Yoti::SignedTimeStamp.new(signed_time_stamp.version, Time.at(time_in_sec)) end + # + # Return Anchor for provided oid. + # + # @deprecated no longer in use + # + # @param [OpenSSL::X509::Certificate] cert + # @param [String] oid + # @param [String] sub_type + # @param [Yoti::SignedTimeStamp] signed_time_stamp + # @param [Array<OpenSSL::X509::Certificate>] x509_certs_list + # + # @return [Yoti::Anchor, nil] + # def get_anchor_by_oid(cert, oid, sub_type, signed_time_stamp, x509_certs_list) asn1_obj = OpenSSL::ASN1.decode(cert) anchor_value = get_anchor_value_by_oid(asn1_obj, oid) - return nil if anchor_value.nil? - - Yoti::Anchor.new(anchor_value, sub_type, signed_time_stamp, x509_certs_list) + Yoti::Anchor.new(anchor_value, sub_type, signed_time_stamp, x509_certs_list) unless anchor_value.nil? end + # + # Return Anchor value for provided oid. + # + # @deprecated no longer in use + # + # @param [OpenSSL::ASN1::Sequence, OpenSSL::ASN1::ASN1Data, Array] obj + # @param [String] oid + # + # @return [String, nil] + # def get_anchor_value_by_oid(obj, oid) case obj when OpenSSL::ASN1::Sequence, Array return get_anchor_value_by_asn1_sequence(obj, oid) when OpenSSL::ASN1::ASN1Data @@ -64,38 +101,167 @@ # In case it's not a valid object nil end + # + # Return Anchor value for ASN1 data. + # + # @deprecated no longer in use + # + # @param [OpenSSL::ASN1::ASN1Data] value + # @param [String] oid + # + # @return [String, nil] + # def get_anchor_value_by_asn1_data(value, oid) if value.respond_to?(:to_s) && value == oid @get_next = true elsif value.respond_to?(:to_s) && @get_next - raw_value = OpenSSL::ASN1.decode(value) - anchor_value = raw_value.value[0].value @get_next = false - return anchor_value + return OpenSSL::ASN1.decode(value).value[0].value end get_anchor_value_by_oid(value, oid) end + # + # Return Anchor value for ASN1 sequence. + # + # @deprecated no longer in use + # + # @param [OpenSSL::ASN1::Sequence, Array] obj + # @param [String] oid + # + # @return [String, nil] + # def get_anchor_value_by_asn1_sequence(obj, oid) obj.each do |child_obj| result = get_anchor_value_by_oid(child_obj, oid) return result unless result.nil? end nil end + # + # Mapping of anchor types to oid. + # + # @deprecated no longer in use + # + # @return [Hash] + # def anchor_types - { 'sources' => '1.3.6.1.4.1.47127.1.1.1', - 'verifiers' => '1.3.6.1.4.1.47127.1.1.2' } + ANCHOR_LIST_KEYS end protected + # # Define whether the search function get_anchor_value_by_oid # should return the next value in the array + # + # @deprecated no longer in use + # + # @return [Boolean] + # attr_reader :get_next + + private + + # + # Mapping of anchor types. + # + ANCHOR_TYPES = { + 'SOURCE' => '1.3.6.1.4.1.47127.1.1.1', + 'VERIFIER' => '1.3.6.1.4.1.47127.1.1.2', + 'UNKNOWN' => '' + }.freeze + + # + # Mapping of anchor list keys. + # + ANCHOR_LIST_KEYS = { + 'sources' => ANCHOR_TYPES['SOURCE'], + 'verifiers' => ANCHOR_TYPES['VERIFIER'], + 'unknown' => ANCHOR_TYPES['UNKNOWN'] + }.freeze + + # + # Get anchor type by oid. + # + # @param [String] oid + # + def get_anchor_type_by_oid(oid) + ANCHOR_TYPES.find { |_key, value| value == oid }.first + end + + # + # Get anchor list key by type. + # + # @param [String] type + # + def get_anchor_list_key_by_type(type) + ANCHOR_LIST_KEYS.find { |_key, value| value == ANCHOR_TYPES[type] }.first + end + + # + # Get anchor from provided certificate list. + # + # @param [Array<OpenSSL::X509::Certificate>] x509_certs_list + # @param [String] sub_type + # @param [Yoti::SignedTimeStamp] signed_time_stamp + # + # @return [Yoti::Anchor] + # + def get_anchor_from_certs(x509_certs_list, sub_type, signed_time_stamp) + x509_certs_list.each do |cert| + ANCHOR_TYPES.each do |_type, oid| + anchor_extension = get_extension_by_oid(cert, oid) + next if anchor_extension.nil? + + return Yoti::Anchor.new( + get_anchor_value(anchor_extension), + sub_type, + signed_time_stamp, + x509_certs_list, + get_anchor_type_by_oid(oid) + ) + end + end + Yoti::Anchor.new('', sub_type, signed_time_stamp, x509_certs_list, 'UNKNOWN') + end + + # + # Get extension for provided oid. + # + # @param [OpenSSL::X509::Certificate] cert + # @param [String] oid + # + # @return [OpenSSL::X509::Extension] + # + def get_extension_by_oid(cert, oid) + cert.extensions.each do |extension| + return extension if extension.oid == oid + end + nil + end + + # + # Return Anchor value. + # + # @param [OpenSSL::X509::Extension] anchor_extension + # + # @return [String, nil] + # + def get_anchor_value(anchor_extension) + decoded_extension = OpenSSL::ASN1.decode(anchor_extension) + extension_value = decoded_extension.value[1] if decoded_extension.value.is_a?(Array) + extension_value_item = extension_value.value if extension_value.is_a?(OpenSSL::ASN1::OctetString) + if extension_value_item.is_a?(String) + decoded = OpenSSL::ASN1.decode(extension_value_item) + return decoded.value[0].value if decoded.value[0].is_a?(OpenSSL::ASN1::ASN1Data) + end + + nil + end end end