lib/app_info/android/signatures/v3.rb in app-info-3.0.0.beta1 vs lib/app_info/android/signatures/v3.rb in app-info-3.0.0.beta2
- old
+ new
@@ -1,127 +1,131 @@
# frozen_string_literal: true
-module AppInfo::Android::Signature
- # Android v3 Signature
- #
- # FULL FORMAT:
- # OFFSET DATA TYPE DESCRIPTION
- # * @+0 bytes uint32: signer size in bytes
- # * @+4 bytes payload signer block
- # * @+0 bytes unit32: signed data size in bytes
- # * @+4 bytes payload signed data block
- # * @+0 bytes unit32: digests with size in bytes
- # * @+0 bytes unit32: digests with size in bytes
- # * @+W bytes unit32: minSDK
- # * @+X+4 bytes unit32: maxSDK
- # * @+Y+4 bytes unit32: signatures with size in bytes
- # * @+Y+4 bytes payload signed data block
- # * @+Z bytes unit32: public key with size in bytes
- # * @+Z+4 bytes payload signed data block
- class V3 < Base
- include AppInfo::Helper::IOBlock
- include AppInfo::Helper::Signatures
- include AppInfo::Helper::Algorithm
+module AppInfo
+ class Android < File
+ module Signature
+ # Android v3 Signature
+ #
+ # FULL FORMAT:
+ # OFFSET DATA TYPE DESCRIPTION
+ # * @+0 bytes uint32: signer size in bytes
+ # * @+4 bytes payload signer block
+ # * @+0 bytes unit32: signed data size in bytes
+ # * @+4 bytes payload signed data block
+ # * @+0 bytes unit32: digests with size in bytes
+ # * @+0 bytes unit32: digests with size in bytes
+ # * @+W bytes unit32: minSDK
+ # * @+X+4 bytes unit32: maxSDK
+ # * @+Y+4 bytes unit32: signatures with size in bytes
+ # * @+Y+4 bytes payload signed data block
+ # * @+Z bytes unit32: public key with size in bytes
+ # * @+Z+4 bytes payload signed data block
+ class V3 < Base
+ include AppInfo::Helper::IOBlock
+ include AppInfo::Helper::Signatures
+ include AppInfo::Helper::Algorithm
- # V3 Signature ID 0xf05368c0
- V3_BLOCK_ID = [0xc0, 0x68, 0x53, 0xf0].freeze
+ # V3 Signature ID 0xf05368c0
+ V3_BLOCK_ID = [0xc0, 0x68, 0x53, 0xf0].freeze
- # V3.1 Signature ID 0x1b93ad61
- V3_1_BLOCK_ID = [0x61, 0xad, 0x93, 0x1b].freeze
+ # V3.1 Signature ID 0x1b93ad61
+ V3_1_BLOCK_ID = [0x61, 0xad, 0x93, 0x1b].freeze
- attr_reader :certificates, :digests
+ attr_reader :certificates, :digests
- def version
- Version::V3
- end
+ def version
+ Version::V3
+ end
- def verify
- begin
- signers_block = singers_block(V3_1_BLOCK_ID)
- rescue NotFoundError
- signers_block = singers_block(V3_BLOCK_ID)
- end
+ def verify
+ begin
+ signers_block = singers_block(V3_1_BLOCK_ID)
+ rescue NotFoundError
+ signers_block = singers_block(V3_BLOCK_ID)
+ end
- @certificates, @digests = verified_certs(signers_block)
- end
+ @certificates, @digests = verified_certs(signers_block)
+ end
- private
+ private
- def verified_certs(signers_block)
- unless (signers = length_prefix_block(signers_block))
- raise SecurityError, 'Not found signers'
- end
+ def verified_certs(signers_block)
+ unless (signers = length_prefix_block(signers_block))
+ raise SecurityError, 'Not found signers'
+ end
- certificates = []
- content_digests = {}
- loop_length_prefix_io(signers, name: 'Singer', logger: logger) do |signer|
- signer_certs, signer_digests = extract_signer_data(signer)
- certificates.concat(signer_certs)
- content_digests.merge!(signer_digests)
- end
- raise SecurityError, 'No signers found' if certificates.empty?
+ certificates = []
+ content_digests = {}
+ loop_length_prefix_io(signers, name: 'Singer', logger: logger) do |signer|
+ signer_certs, signer_digests = extract_signer_data(signer)
+ certificates.concat(signer_certs)
+ content_digests.merge!(signer_digests)
+ end
+ raise SecurityError, 'No signers found' if certificates.empty?
- [certificates, content_digests]
- end
+ [certificates, content_digests]
+ end
- def extract_signer_data(signer)
- # raw data
- signed_data = length_prefix_block(signer)
+ def extract_signer_data(signer)
+ # raw data
+ signed_data = length_prefix_block(signer)
- # TODO: verify min_sdk and max_sdk
- min_sdk = signer.read(UINT32_SIZE)
- max_sdk = signer.read(UINT32_SIZE)
+ # TODO: verify min_sdk and max_sdk
+ min_sdk = signer.read(UINT32_SIZE)
+ max_sdk = signer.read(UINT32_SIZE)
- signatures = length_prefix_block(signer)
- public_key = length_prefix_block(signer, raw: true)
+ signatures = length_prefix_block(signer)
+ public_key = length_prefix_block(signer, raw: true)
- algorithems = signature_algorithms(signatures)
- raise SecurityError, 'No signatures found' if algorithems.empty?
+ algorithems = signature_algorithms(signatures)
+ raise SecurityError, 'No signatures found' if algorithems.empty?
- # find best algorithem to verify signed data with public key and signature
- unless best_algorithem = best_algorithem(algorithems)
- raise SecurityError, 'No supported signatures found'
- end
+ # find best algorithem to verify signed data with public key and signature
+ unless best_algorithem = best_algorithem(algorithems)
+ raise SecurityError, 'No supported signatures found'
+ end
- algorithems_digest = best_algorithem[:digest]
- signature = best_algorithem[:signature]
+ algorithems_digest = best_algorithem[:digest]
+ signature = best_algorithem[:signature]
- pkey = OpenSSL::PKey.read(public_key)
- digest = OpenSSL::Digest.new(algorithems_digest)
- verified = pkey.verify(digest, signature, signed_data.string)
- raise SecurityError, "#{algorithems_digest} signature did not verify" unless verified
+ pkey = OpenSSL::PKey.read(public_key)
+ digest = OpenSSL::Digest.new(algorithems_digest)
+ verified = pkey.verify(digest, signature, signed_data.string)
+ raise SecurityError, "#{algorithems_digest} signature did not verify" unless verified
- # verify algorithm ID full equal (and sort) between digests and signature
- digests = length_prefix_block(signed_data)
- content_digests = signed_data_digests(digests)
- content_digest = content_digests[algorithems_digest]&.fetch(:content)
+ # verify algorithm ID full equal (and sort) between digests and signature
+ digests = length_prefix_block(signed_data)
+ content_digests = signed_data_digests(digests)
+ content_digest = content_digests[algorithems_digest]&.fetch(:content)
- unless content_digest
- raise SecurityError,
- 'Signature algorithms don\'t match between digests and signatures records'
- end
+ unless content_digest
+ raise SecurityError,
+ 'Signature algorithms don\'t match between digests and signatures records'
+ end
- previous_digest = content_digests.fetch(algorithems_digest)
- content_digests[algorithems_digest] = content_digest
- if previous_digest && previous_digest[:content] != content_digest
- raise SecurityError,
- 'Signature algorithms don\'t match between digests and signatures records'
- end
+ previous_digest = content_digests.fetch(algorithems_digest)
+ content_digests[algorithems_digest] = content_digest
+ if previous_digest && previous_digest[:content] != content_digest
+ raise SecurityError,
+ 'Signature algorithms don\'t match between digests and signatures records'
+ end
- certificates = length_prefix_block(signed_data)
- certs = signed_data_certs(certificates)
- raise SecurityError, 'No certificates listed' if certs.empty?
+ certificates = length_prefix_block(signed_data)
+ certs = signed_data_certs(certificates)
+ raise SecurityError, 'No certificates listed' if certs.empty?
- main_cert = certs[0]
- if main_cert.public_key.to_der != pkey.to_der
- raise SecurityError, 'Public key mismatch between certificate and signature record'
- end
+ main_cert = certs[0]
+ if main_cert.public_key.to_der != pkey.to_der
+ raise SecurityError, 'Public key mismatch between certificate and signature record'
+ end
- additional_attrs = length_prefix_block(signed_data)
- verify_additional_attrs(additional_attrs, certs)
+ additional_attrs = length_prefix_block(signed_data)
+ verify_additional_attrs(additional_attrs, certs)
- [certs, content_digests]
+ [certs, content_digests]
+ end
+ end
+
+ register(Version::V3, V3)
end
end
-
- register(Version::V3, V3)
end