Class: MooTool::Models::IMG4::File
- Inherits:
-
Object
- Object
- MooTool::Models::IMG4::File
show all
- Includes:
- Helpers::IMG4
- Defined in:
- lib/mootool/models/img4/file.rb
Overview
An IMG4 file, or, occasionally, a file read in from another source
Constant Summary
collapse
- DER_PAYLOADS =
%w[trst].freeze
Helpers::IMG4::DECODE_TAGS, Helpers::IMG4::FIRMWARE_TAGS, Helpers::IMG4::HASH_LENGTHS, Helpers::IMG4::KEY_INSTANCE_TAGS, Helpers::IMG4::KVP_TAGS, Helpers::IMG4::OCTET_TAGS, Helpers::IMG4::SEQUENCE_TAGS, Helpers::IMG4::SIGNATURE_TAGS
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
#construct, #construct_object, #decode_construct, parse_4cc
Constructor Details
#initialize(der, filename = nil) ⇒ File
Returns a new instance of File.
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
# File 'lib/mootool/models/img4/file.rb', line 59
def initialize(der, filename = nil)
MooTool::Models::FileIndex.load '/Users/rickmark/Desktop/index.json'
@filename = filename
raw_data = der.is_a?(MooTool::Models::Digest) ? der.value : der
@hashes = [MooTool::Models::Digest.create(::Digest::SHA384.digest(raw_data))]
@data = OpenSSL::ASN1.decode(raw_data)
@type = @data.value[0].value
@content = {}
case @type
when 'IM4P'
@content[:IM4P] = MooTool::Models::IMG4::IMG4Payload.new(@data)
when 'IM4M'
@content[:IM4M] = MooTool::Models::IMG4::IMG4Manifest.new(@data)
when 'IMG4'
@content[:IM4P] = MooTool::Models::IMG4::IMG4Payload.new(@data.value[1])
@content[:IM4M] = MooTool::Models::IMG4::IMG4Manifest.new(@data.value[2])
when 'secb'
@value = construct(@data)
@content[:secb] = @value.drop(1).map do |entry|
case entry[0]
when 'trst', 'rssl'
{ entry[0].to_sym => File.parse_certificates(entry.drop(1)) }
when 'rvok'
{ entry[0].to_sym => entry[1] }
when 'trpk'
{ entry[0].to_sym => entry.drop(1).map { |e| MooTool::Models::ECCPublicKey.new e } }
end
end.reduce(&:merge)
when 'comb'
@value = construct(@data)
@content[:comb] = @value.drop(1).map do |entry|
{ entry[0] => File.new(entry[1]) }
end.reduce(&:merge)
else
@content = @value.map(&:to_h).reduce(&:merge)
end
end
|
Instance Attribute Details
#file_index ⇒ Object
Returns the value of attribute file_index.
9
10
11
|
# File 'lib/mootool/models/img4/file.rb', line 9
def file_index
@file_index
end
|
#manifest ⇒ Object
Returns the value of attribute manifest.
9
10
11
|
# File 'lib/mootool/models/img4/file.rb', line 9
def manifest
@manifest
end
|
#payload ⇒ Object
Returns the value of attribute payload.
9
10
11
|
# File 'lib/mootool/models/img4/file.rb', line 9
def payload
@payload
end
|
Class Method Details
.load(path) ⇒ Object
15
16
17
18
19
20
21
22
23
24
|
# File 'lib/mootool/models/img4/file.rb', line 15
def self.load(path)
case path
when FileLocation
data = ::File.binread(path.fullname)
new(data, path.fullname)
when String, Pathname
data = ::File.binread(path)
new(data, path)
end
end
|
.parse_certificates(certificates) ⇒ Object
35
36
37
38
39
40
41
|
# File 'lib/mootool/models/img4/file.rb', line 35
def self.parse_certificates(certificates)
certificates.map do |certificate|
certificate_data = certificate.value if certificate.is_a?(Models::Digest)
certificate_data = certificate.to_der if certificate.respond_to?(:to_der)
Models::Certificate.new OpenSSL::X509::Certificate.new(certificate_data)
end
end
|
.parse_signature(signature) ⇒ Object
26
27
28
29
30
31
32
33
|
# File 'lib/mootool/models/img4/file.rb', line 26
def self.parse_signature(signature)
signature = signature.value if signature.is_a?(OpenSSL::ASN1::OctetString)
if signature.size > 128
Models::Digest.create(signature, 'RSASignature')
else
::MooTool::Models::ECCSignature.create(signature)
end
end
|
Instance Method Details
#basename ⇒ Object
179
180
181
182
183
|
# File 'lib/mootool/models/img4/file.rb', line 179
def basename
basename = ::File.basename(@filename)
extension = ::File.extname(basename)
"#{basename.chomp(extension)}.#{@type}"
end
|
185
186
187
188
|
# File 'lib/mootool/models/img4/file.rb', line 185
def
output_path = ::File.join(::File.dirname(@filename), basename)
::File.write(output_path, @payload)
end
|
#hashes ⇒ Object
190
191
192
193
194
195
196
197
198
199
200
|
# File 'lib/mootool/models/img4/file.rb', line 190
def hashes
result = @hashes.dup
result += @content[:comb].flat_map { |_k, v| v.hashes } if @content[:comb]
result += @content[:IM4M].hashes if @content[:IM4M]
result += @content[:IM4P].hashes if @content[:IM4P]
result.map { |h| h.respond_to?(:value) ? h.value : h }.uniq.map { |h| Models::Digest.create(h) }
end
|
#manifest? ⇒ Boolean
175
176
177
|
# File 'lib/mootool/models/img4/file.rb', line 175
def manifest?
!@content[:IM4M].nil?
end
|
#manifest_type ⇒ Object
47
48
49
|
# File 'lib/mootool/models/img4/file.rb', line 47
def manifest_type
@content[:IM4M]&.type&.to_sym
end
|
#parse_element(element) ⇒ Object
150
151
152
|
# File 'lib/mootool/models/img4/file.rb', line 150
def parse_element(element)
{ element.value[0].value.to_sym => element.value[1].value }
end
|
#parse_pair(input) ⇒ Object
154
155
156
157
158
|
# File 'lib/mootool/models/img4/file.rb', line 154
def parse_pair(input)
input.value.to_a.each_slice(2).to_h do |key, value|
[key.value, value]
end
end
|
#payload? ⇒ Boolean
171
172
173
|
# File 'lib/mootool/models/img4/file.rb', line 171
def payload?
!@content[:IM4P].nil?
end
|
#payload_type ⇒ Object
43
44
45
|
# File 'lib/mootool/models/img4/file.rb', line 43
def payload_type
@content[:IM4P]&.type&.to_sym
end
|
#print(friendly) ⇒ Object
202
203
204
205
206
207
208
209
210
211
212
213
214
|
# File 'lib/mootool/models/img4/file.rb', line 202
def print(friendly)
output = to_h
if friendly
mappings = IMG4.mappings
output.deep_transform_keys! do |key|
new_key = mappings.dig(key.to_s, 'title') || mappings.dig(key.to_s, 'description') || key
new_key.respond_to?(:to_sym) ? new_key.to_sym : new_key
end
end
ap(output)
end
|
#to_h ⇒ Object
51
52
53
54
55
56
57
|
# File 'lib/mootool/models/img4/file.rb', line 51
def to_h
content = @content.transform_values(&:inspect)
content[:file_type] = @type
content[:hashes] = hashes
content
end
|
#types ⇒ Object
160
161
162
163
164
165
|
# File 'lib/mootool/models/img4/file.rb', line 160
def types
result = [payload_type]
result += @content[:comb].keys if @content[:comb]
result += @content[:secb].keys if @content[:secb]
result.compact.map(&:to_sym)
end
|
#validate_signature ⇒ Object
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
# File 'lib/mootool/models/img4/file.rb', line 106
def validate_signature
leaf_certificate = validted_certificate_chain
[OpenSSL::Digest.new('SHA384'), OpenSSL::Digest.new('SHA256')].flat_map do |digest|
values = %i[IM4M IM4P].map do |kind|
@content[kind]&.to_bytes
end.compact
hashes = values.map do |value|
OpenSSL::Digest::SHA384.digest(value)
end.compact
signatures = %i[IM4P IM4M].map do |kind|
signature = @content[kind]&.signature
signature.respond_to?(:value) ? signature.value : signature
end.compact
signatures.flat_map do |signature|
value_result = values.map do |value|
{ digest.hexdigest(value) => leaf_certificate.public_key.verify(digest, signature, value) }
end
hashes_result = hashes.map do |hash|
{ digest.hexdigest(hash) => leaf_certificate.public_key.verify(digest, signature, hash) }
end
hash_hashes_result = hashes.map do |hash|
{ digest.hexdigest(hash) => leaf_certificate.public_key.verify(digest, signature, digest.digest(hash)) }
end
join_result = [
{ digest.hexdigest(hashes.join) => leaf_certificate.public_key.verify(digest, signature, hashes.join) }
]
value_result + hashes_result + hash_hashes_result + join_result
end
end.reduce(&:merge)
end
|
#validted_certificate_chain ⇒ Object
102
103
104
|
# File 'lib/mootool/models/img4/file.rb', line 102
def validted_certificate_chain
@content[:IM4M].certificates.last
end
|