# frozen_string_literal: true module AppInfo class Android < File # Android Signature # # Support digest and length: # # RSA:1024、2048、4096、8192、16384 # EC:NIST P-256、P-384、P-521 # DSA:1024、2048、3072 module Signature class VersionError < Error; end class SecurityError < Error; end class NotFoundError < NotFoundError; end module Version V1 = 1 V2 = 2 V3 = 3 V4 = 4 end # All registerd verions to verify # # key is the version # value is the class @versions = {} class << self # Verify Android Signature # # @example Get unverified v1 certificates, verified v2 certificates, # and not found v3 certificate # # signature.versions(parser) # # => [ # # { # # version: 1, # # verified: false, # # certificates: [, ...], # # verifier: AppInfo::Androig::Signature # # }, # # { # # version: 2, # # verified: false, # # certificates: [, ...], # # verifier: AppInfo::Androig::Signature # # }, # # { # # version: 3 # # } # # ] # @todo version 4 no implantation yet # @param [AppInfo::File] parser # @param [Version, Integer] min_version # @return [Array] versions def verify(parser, min_version: Version::V4) min_version = min_version.to_i if min_version.is_a?(String) if min_version && min_version > Version::V4 raise VersionError, "No signature found in #{min_version} scheme or newer for android file" end if min_version.zero? raise VersionError, "Unkonwn version: #{min_version}, avaiables in 1/2/3 and 4 (no implantation yet)" end # try full version signatures if min_version is nil versions = min_version.downto(Version::V1).each_with_object([]) do |version, signatures| next unless kclass = fetch(version) data = { version: version } begin verifier = kclass.verify(parser) data[:verified] = verifier.verified data[:certificates] = verifier.certificates data[:verifier] = verifier rescue SecurityError, NotFoundError # not this version, try the low version ensure signatures << data end end versions.sort_by { |entry| entry[:version] } end def registered @versions.keys end def register(version, verifier) @versions[version] = verifier end def fetch(version) @versions[version] end def exist?(version) @versions.key?(version) end end UINT32_MAX_VALUE = 2_147_483_647 UINT32_SIZE = 4 UINT64_SIZE = 8 end end end require 'app_info/android/signatures/base'