costan-tem_ruby 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +45 -0
- data/LICENSE +21 -0
- data/Manifest +75 -0
- data/README +8 -0
- data/Rakefile +23 -0
- data/bin/tem_bench +9 -0
- data/bin/tem_ca +13 -0
- data/bin/tem_irb +11 -0
- data/bin/tem_proxy +65 -0
- data/bin/tem_stat +35 -0
- data/dev_ca/ca_cert.cer +0 -0
- data/dev_ca/ca_cert.pem +32 -0
- data/dev_ca/ca_key.pem +27 -0
- data/dev_ca/config.yml +14 -0
- data/lib/tem/_cert.rb +158 -0
- data/lib/tem/apdus/buffers.rb +89 -0
- data/lib/tem/apdus/keys.rb +64 -0
- data/lib/tem/apdus/lifecycle.rb +13 -0
- data/lib/tem/apdus/tag.rb +38 -0
- data/lib/tem/auto_conf.rb +25 -0
- data/lib/tem/builders/abi.rb +482 -0
- data/lib/tem/builders/assembler.rb +314 -0
- data/lib/tem/builders/crypto.rb +124 -0
- data/lib/tem/builders/isa.rb +120 -0
- data/lib/tem/ca.rb +114 -0
- data/lib/tem/definitions/abi.rb +65 -0
- data/lib/tem/definitions/assembler.rb +23 -0
- data/lib/tem/definitions/isa.rb +188 -0
- data/lib/tem/ecert.rb +77 -0
- data/lib/tem/hive.rb +18 -0
- data/lib/tem/keys/asymmetric.rb +116 -0
- data/lib/tem/keys/key.rb +48 -0
- data/lib/tem/keys/symmetric.rb +47 -0
- data/lib/tem/sec_exec_error.rb +63 -0
- data/lib/tem/seclosures.rb +81 -0
- data/lib/tem/secpack.rb +107 -0
- data/lib/tem/tem.rb +31 -0
- data/lib/tem/toolkit.rb +101 -0
- data/lib/tem/transport/auto_configurator.rb +87 -0
- data/lib/tem/transport/java_card_mixin.rb +99 -0
- data/lib/tem/transport/jcop_remote_protocol.rb +59 -0
- data/lib/tem/transport/jcop_remote_server.rb +171 -0
- data/lib/tem/transport/jcop_remote_transport.rb +65 -0
- data/lib/tem/transport/pcsc_transport.rb +87 -0
- data/lib/tem/transport/transport.rb +10 -0
- data/lib/tem_ruby.rb +47 -0
- data/tem_ruby.gemspec +35 -0
- data/test/_test_cert.rb +70 -0
- data/test/builders/test_abi_builder.rb +298 -0
- data/test/tem_test_case.rb +26 -0
- data/test/tem_unit/test_tem_alu.rb +33 -0
- data/test/tem_unit/test_tem_bound_secpack.rb +51 -0
- data/test/tem_unit/test_tem_branching.rb +56 -0
- data/test/tem_unit/test_tem_crypto_asymmetric.rb +123 -0
- data/test/tem_unit/test_tem_crypto_hash.rb +35 -0
- data/test/tem_unit/test_tem_crypto_pstore.rb +53 -0
- data/test/tem_unit/test_tem_crypto_random.rb +25 -0
- data/test/tem_unit/test_tem_emit.rb +23 -0
- data/test/tem_unit/test_tem_memory.rb +48 -0
- data/test/tem_unit/test_tem_memory_compare.rb +65 -0
- data/test/tem_unit/test_tem_output.rb +32 -0
- data/test/tem_unit/test_tem_yaml_secpack.rb +47 -0
- data/test/test_driver.rb +108 -0
- data/test/test_exceptions.rb +35 -0
- data/test/transport/test_auto_configurator.rb +114 -0
- data/test/transport/test_java_card_mixin.rb +90 -0
- data/test/transport/test_jcop_remote.rb +82 -0
- data/timings/blank_bound_secpack.rb +18 -0
- data/timings/blank_sec.rb +14 -0
- data/timings/devchip_decrypt.rb +9 -0
- data/timings/post_buffer.rb +10 -0
- data/timings/simple_apdu.rb +5 -0
- data/timings/timings.rb +64 -0
- data/timings/vm_perf.rb +140 -0
- data/timings/vm_perf_bound.rb +141 -0
- metadata +201 -0
@@ -0,0 +1,314 @@
|
|
1
|
+
# :nodoc: namespace
|
2
|
+
module Tem::Builders
|
3
|
+
|
4
|
+
# Builder class for the code assembler builder.
|
5
|
+
class Assembler
|
6
|
+
# Creates a builder targeting a module / class.
|
7
|
+
#
|
8
|
+
# The given parameter should be a class or module.
|
9
|
+
def self.define_assembler(class_or_module) # :yields: abi
|
10
|
+
yield new(class_or_module)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Defines the ISA targeted by the assembler.
|
14
|
+
#
|
15
|
+
# This method should be called early in the assembler definition. It creates
|
16
|
+
# the proxy and builder classes for the assembling process.
|
17
|
+
def target_isa(isa_module)
|
18
|
+
@isa = isa_module
|
19
|
+
target.const_set :Isa, @isa
|
20
|
+
@abi = @isa.const_get :Abi
|
21
|
+
target.const_set :Abi, @abi
|
22
|
+
|
23
|
+
define_proxy_class
|
24
|
+
define_builder_class
|
25
|
+
augment_target
|
26
|
+
end
|
27
|
+
|
28
|
+
# Defines the methods for implementing a stack directive.
|
29
|
+
#
|
30
|
+
# The following options are supported:
|
31
|
+
# label:: the label serving as the stack marker (required)
|
32
|
+
# slot_type:: the ABI type representing a stack slot
|
33
|
+
#
|
34
|
+
# The following method is defined in the proxy for a directive named 'name':
|
35
|
+
# * name(slots = 0) -> places a stack marker and allocates stack slots
|
36
|
+
def stack_directive(name, options)
|
37
|
+
unless @proxy_class
|
38
|
+
raise "target_isa must be called before other builder methods"
|
39
|
+
end
|
40
|
+
# Capture these in the closure.
|
41
|
+
stack_label = options[:label]
|
42
|
+
slot_length = @abi.send :"#{options[:slot_type]}_length"
|
43
|
+
proxy_defines = Proc.new do
|
44
|
+
define_method name.to_sym do |*args|
|
45
|
+
case args.length
|
46
|
+
when 0
|
47
|
+
slots = 0
|
48
|
+
when 1
|
49
|
+
slots = args.first
|
50
|
+
else
|
51
|
+
raise "#{name}: given #{args.length} arguments, wanted at most 1"
|
52
|
+
end
|
53
|
+
@assembler.emit_label stack_label
|
54
|
+
if slots > 0
|
55
|
+
@assembler.emit_bytes name, :emit => Array.new(slots * slot_length, 0)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
@proxy_class.class_eval &proxy_defines
|
60
|
+
(class << @proxy_class; self; end).module_eval &proxy_defines
|
61
|
+
end
|
62
|
+
|
63
|
+
# Defines the methods for implementing a labeling directive.
|
64
|
+
#
|
65
|
+
# The following method is defined in the proxy for a directive named 'name':
|
66
|
+
# * name(label_name) -> creates a label named label_name at the current byte
|
67
|
+
def label_directive(name, options = {})
|
68
|
+
unless @proxy_class
|
69
|
+
raise "target_isa must be called before other builder methods"
|
70
|
+
end
|
71
|
+
proxy_defines = Proc.new do
|
72
|
+
define_method name.to_sym do |label_name|
|
73
|
+
@assembler.emit_label label_name.to_sym
|
74
|
+
end
|
75
|
+
end
|
76
|
+
@proxy_class.class_eval &proxy_defines
|
77
|
+
(class << @proxy_class; self; end).module_eval &proxy_defines
|
78
|
+
end
|
79
|
+
|
80
|
+
# Defines the methods for implementing a special label directive.
|
81
|
+
#
|
82
|
+
# The following method is defined in the proxy for a directive named 'name':
|
83
|
+
# * name -> creates a label named label_name at the current byte
|
84
|
+
def special_label_directive(name, label_name)
|
85
|
+
unless @proxy_class
|
86
|
+
raise "target_isa must be called before other builder methods"
|
87
|
+
end
|
88
|
+
proxy_defines = Proc.new do
|
89
|
+
define_method name.to_sym do
|
90
|
+
@assembler.emit_label label_name.to_sym
|
91
|
+
end
|
92
|
+
end
|
93
|
+
@proxy_class.class_eval &proxy_defines
|
94
|
+
(class << @proxy_class; self; end).module_eval &proxy_defines
|
95
|
+
end
|
96
|
+
|
97
|
+
# Defines the methods for implementing a zero-inserting directive.
|
98
|
+
#
|
99
|
+
# The following method is defined in the proxy for a directive named 'name':
|
100
|
+
# * name(abi_type, count = 1) -> creates count zeros of abi_type
|
101
|
+
def zeros_directive(name, options = {})
|
102
|
+
unless @proxy_class
|
103
|
+
raise "target_isa must be called before other builder methods"
|
104
|
+
end
|
105
|
+
# Capture this in the closure.
|
106
|
+
abi = @abi
|
107
|
+
proxy_defines = Proc.new do
|
108
|
+
define_method name.to_sym do |*args|
|
109
|
+
if args.length == 1 || args.length == 2
|
110
|
+
type_name, count = args[0], args[1] || 1
|
111
|
+
else
|
112
|
+
raise "#{name}: given #{args.length} arguments, wanted 1 or 2"
|
113
|
+
end
|
114
|
+
bytes = count * abi.send(:"#{type_name}_length")
|
115
|
+
@assembler.emit_bytes name, :emit => Array.new(bytes, 0)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
@proxy_class.class_eval &proxy_defines
|
119
|
+
(class << @proxy_class; self; end).module_eval &proxy_defines
|
120
|
+
end
|
121
|
+
|
122
|
+
# Defines the methods for implementing a data-emitting directive.
|
123
|
+
#
|
124
|
+
# The following method is defined in the proxy for a directive named 'name':
|
125
|
+
# * name(abi_type, values = 1) -> emits the given values as abi_type
|
126
|
+
def data_directive(name, options = {})
|
127
|
+
unless @proxy_class
|
128
|
+
raise "target_isa must be called before other builder methods"
|
129
|
+
end
|
130
|
+
# Capture this in the closure.
|
131
|
+
abi = @abi
|
132
|
+
proxy_defines = Proc.new do
|
133
|
+
define_method name.to_sym do |abi_type, values|
|
134
|
+
values = [values] unless values.instance_of? Array
|
135
|
+
data = []
|
136
|
+
values.each { |value| data += abi.send :"to_#{abi_type}", value }
|
137
|
+
@assembler.emit_bytes :immed, :emit => data
|
138
|
+
end
|
139
|
+
end
|
140
|
+
@proxy_class.class_eval &proxy_defines
|
141
|
+
(class << @proxy_class; self; end).module_eval &proxy_defines
|
142
|
+
end
|
143
|
+
|
144
|
+
# (private) Defines the builder class used during assembly.
|
145
|
+
#
|
146
|
+
# Builders maintain intermediate results during the assembly process. In a
|
147
|
+
# nutshell, a builder collects the bytes, labels and linker directives, and
|
148
|
+
# puts them together at the end of the assembly process.
|
149
|
+
#
|
150
|
+
# Builder classes are synthesized automatically if they don't already exist.
|
151
|
+
# To have a builder class inherit from another class, define it before calling
|
152
|
+
# target_isa. Builder classes are saved as the Builder constant in the
|
153
|
+
# assembler class.
|
154
|
+
#
|
155
|
+
# Builder classes are injected the code in Assembler::CodeBuilderBase. Look
|
156
|
+
# there for override hooks into the assembly process.
|
157
|
+
def define_builder_class
|
158
|
+
if @target.const_defined? :Builder
|
159
|
+
@builder_class = @taget.const_get :Builder
|
160
|
+
else
|
161
|
+
@builder_class = Class.new
|
162
|
+
@target.const_set :Builder, @builder_class
|
163
|
+
end
|
164
|
+
@builder_class.send :include, Assembler::CodeBuilderBase
|
165
|
+
end
|
166
|
+
private :define_builder_class
|
167
|
+
|
168
|
+
# (private) Defines the proxy class used during assembly.
|
169
|
+
#
|
170
|
+
# The proxy class is yielded to the block given to the assemble call, which
|
171
|
+
# provides the code to be assembled. For clarity, the proxy class is
|
172
|
+
# synthesized so it only contains the methods that are useful for assembly.
|
173
|
+
#
|
174
|
+
# The proxy class is always automatically synthesized, and is available under
|
175
|
+
# the constant Proxy in the assembler class.
|
176
|
+
def define_proxy_class
|
177
|
+
@proxy_class = Class.new Assembler::ProxyBase
|
178
|
+
target.const_set :Proxy, @proxy_class
|
179
|
+
|
180
|
+
@proxy_class.const_set :Abi, @abi
|
181
|
+
@proxy_class.const_set :Isa, @isa
|
182
|
+
|
183
|
+
# Capture the ISA and ABI in the closure.
|
184
|
+
isa = @isa
|
185
|
+
proxy_defines = Proc.new do
|
186
|
+
isa.instance_methods.each do |method|
|
187
|
+
if method[0, 5] == 'emit_'
|
188
|
+
isa_method_msg = method.to_sym
|
189
|
+
proxy_method_name = method[5, method.length].to_sym
|
190
|
+
define_method proxy_method_name do |*args|
|
191
|
+
emit_data = isa.send isa_method_msg, *args
|
192
|
+
@assembler.emit_bytes proxy_method_name, emit_data
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
@proxy_class.class_eval &proxy_defines
|
198
|
+
(class << @proxy_class; self; end).module_eval &proxy_defines
|
199
|
+
end
|
200
|
+
private :define_proxy_class
|
201
|
+
|
202
|
+
# (private) Augments the target with the assemble method.
|
203
|
+
def augment_target
|
204
|
+
# Capture this data in the closure.
|
205
|
+
proxy_class = @proxy_class
|
206
|
+
builder_class = @builder_class
|
207
|
+
defines = Proc.new do
|
208
|
+
# Assembles code.
|
209
|
+
def assemble(&block)
|
210
|
+
_assemble block
|
211
|
+
end
|
212
|
+
|
213
|
+
# Internal method for assembling code.
|
214
|
+
#
|
215
|
+
# We need to use a block to define this method, so we can capture the
|
216
|
+
# outer variables (proxy_class and builder_class) in its closure. However,
|
217
|
+
# blocks can't take blocks as parameters (at least not in MRI 1.8). So
|
218
|
+
# we use a regular method definition (assemble) which wraps the block
|
219
|
+
# into a Proc received by _assemble.
|
220
|
+
define_method :_assemble do |block|
|
221
|
+
code_builder = builder_class.new
|
222
|
+
code_builder.start_assembling
|
223
|
+
proxy = proxy_class.new(code_builder)
|
224
|
+
block.call proxy
|
225
|
+
code_builder.done_assembling proxy
|
226
|
+
end
|
227
|
+
private :_assemble
|
228
|
+
end
|
229
|
+
@target.class_eval &defines
|
230
|
+
(class << @target; self; end).module_eval &defines
|
231
|
+
end
|
232
|
+
|
233
|
+
# The module / class impacted by the builder.
|
234
|
+
attr_reader :target
|
235
|
+
|
236
|
+
# Creates a builder targeting a module / class.
|
237
|
+
def initialize(target)
|
238
|
+
@target = target
|
239
|
+
@isa, @abi, @proxy = nil, nil, nil
|
240
|
+
end
|
241
|
+
private_class_method :new
|
242
|
+
end # class Assembler
|
243
|
+
|
244
|
+
|
245
|
+
# Base class for the assemblers' proxy objects.
|
246
|
+
#
|
247
|
+
# The proxy object is the object that is yielded out of an assembler's
|
248
|
+
# assemble class method.
|
249
|
+
class Assembler::ProxyBase
|
250
|
+
def initialize(assembler)
|
251
|
+
@assembler = assembler
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# Module injected into the assembler's code builder class.
|
256
|
+
module Assembler::CodeBuilderBase
|
257
|
+
# Called by assemble before its associated block receives control.
|
258
|
+
#
|
259
|
+
# This method is responsible for setting up the state needed by the emit_
|
260
|
+
# methods.
|
261
|
+
def start_assembling
|
262
|
+
@bytes = []
|
263
|
+
@link_directives = []
|
264
|
+
@line_info = []
|
265
|
+
@labels = {}
|
266
|
+
end
|
267
|
+
|
268
|
+
# Emits code or data bytes, with associated link directives.
|
269
|
+
def emit_bytes(emit_atom_name, emit_data)
|
270
|
+
(emit_data[:link_directives] || []).each do |directive|
|
271
|
+
directive[:offset] += @bytes.length
|
272
|
+
@link_directives << directive
|
273
|
+
end
|
274
|
+
|
275
|
+
emit_data[:emit] ||= []
|
276
|
+
if emit_data[:emit].length > 0
|
277
|
+
@line_info << [@bytes.length, emit_atom_name, Kernel.caller(2)]
|
278
|
+
end
|
279
|
+
@bytes += emit_data[:emit] || []
|
280
|
+
end
|
281
|
+
|
282
|
+
# Emits labels, which are symbolic names for addresses.
|
283
|
+
def emit_label(label_name)
|
284
|
+
raise "label #{label_name} already defined" if @labels[label_name]
|
285
|
+
@labels[label_name] = @bytes.length
|
286
|
+
end
|
287
|
+
|
288
|
+
# Called by assemble after its associated block returns.
|
289
|
+
#
|
290
|
+
# This method is responsible for the final assembly steps (i.e. linking) and
|
291
|
+
# returning a processed result. The method's result is returned by assemble.
|
292
|
+
def done_assembling(proxy)
|
293
|
+
# Process link directives.
|
294
|
+
abi = proxy.class.const_get :Abi
|
295
|
+
@link_directives.each do |directive|
|
296
|
+
if label = directive[:label]
|
297
|
+
raise "Label #{label} undefined" unless address = @labels[label]
|
298
|
+
else
|
299
|
+
address = directive[:address]
|
300
|
+
end
|
301
|
+
if directive[:relative]
|
302
|
+
address -= directive[:offset] + directive[:relative]
|
303
|
+
end
|
304
|
+
address_bytes = abi.send :"signed_to_#{directive[:type]}", address
|
305
|
+
@bytes[directive[:offset], address_bytes.length] = *address_bytes
|
306
|
+
end
|
307
|
+
|
308
|
+
# Wrap all the built data into a nice package and return it.
|
309
|
+
{ :bytes => @bytes, :link_directives => @link_direcives, :labels => @labels,
|
310
|
+
:line_info => @line_info }
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
end # namespace Tem::Builders
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
|
4
|
+
# :nodoc: namespace
|
5
|
+
module Tem::Builders
|
6
|
+
|
7
|
+
# Builder class and namespace for the cryptography builder.
|
8
|
+
class Crypto < Abi
|
9
|
+
# Creates a builder targeting a module / class.
|
10
|
+
#
|
11
|
+
# The given parameter should be a class or module
|
12
|
+
def self.define_crypto(class_or_module) # :yields: crypto
|
13
|
+
yield new(class_or_module)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Defines the methods for handling an asymmetric (public/private) key.
|
17
|
+
#
|
18
|
+
# ssl_class should be a class in OpenSSL::PKey. privkey_abi_type and
|
19
|
+
# pubkey_abi_type should be ABI types similar to those produced by
|
20
|
+
# packed_variable_length_numbers.
|
21
|
+
#
|
22
|
+
# The following methods are defined for a type named 'name':
|
23
|
+
# * read_private_name(array, offset) -> key
|
24
|
+
# * to_private_name(key) -> array
|
25
|
+
# * private_name_class -> Class
|
26
|
+
# * read_public_name(array, offset) -> key
|
27
|
+
# * to_public_name(key) -> array
|
28
|
+
# * public_name_class -> Class
|
29
|
+
def asymmetric_key(name, ssl_class, privkey_abi_type, pubkey_abi_type,
|
30
|
+
hooks = {})
|
31
|
+
object_wrapper "private_#{name}", Tem::Keys::Asymmetric,
|
32
|
+
[privkey_abi_type, nil],
|
33
|
+
:read => hooks[:read_private] || hooks[:read] ||
|
34
|
+
lambda { |k| Tem::Keys::Asymmetric.new k },
|
35
|
+
:to => hooks[:to_private] || hooks[:to] ||
|
36
|
+
lambda { |k| k.ssl_key },
|
37
|
+
:new => hooks[:new_private] || hooks[:new] ||
|
38
|
+
lambda { |k| ssl_class.new }
|
39
|
+
object_wrapper "public_#{name}", Tem::Keys::Asymmetric,
|
40
|
+
[pubkey_abi_type, nil],
|
41
|
+
:read => hooks[:read_public] || hooks[:read] ||
|
42
|
+
lambda { |k| Tem::Keys::Asymmetric.new k },
|
43
|
+
:to => hooks[:to_public] || hooks[:to] ||
|
44
|
+
lambda { |k| k.ssl_key },
|
45
|
+
:new => hooks[:new_private] || hooks[:new] ||
|
46
|
+
lambda { |k| ssl_class.new }
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Defines the methods for a symmetric key.
|
51
|
+
#
|
52
|
+
# cipher_class should be a class in OpenSSL::Cipher. key_abi_type should be
|
53
|
+
# an ABI type similar to that produced by fixed_string.
|
54
|
+
#
|
55
|
+
# The following methods are defined for a type named 'name':
|
56
|
+
# * read_name(array, offset) -> object
|
57
|
+
# * to_name(object) -> array
|
58
|
+
# * name_class -> Class
|
59
|
+
def symmetric_key(name, cipher_class, cipher_name, key_abi_type, hooks = {})
|
60
|
+
object_wrapper name, Tem::Keys::Symmetric, [key_abi_type, :key],
|
61
|
+
:read => lambda { |k| Tem::Keys::Symmetric.new k },
|
62
|
+
:to => lambda { |k| k.ssl_key },
|
63
|
+
:new => lambda { |klass|
|
64
|
+
k = cipher_class cipher_name
|
65
|
+
|
66
|
+
unless k.respond_to? :key
|
67
|
+
# Some ciphers don't give back the key that they receive.
|
68
|
+
# We need to synthesize that.
|
69
|
+
class << k
|
70
|
+
def key=(new_key)
|
71
|
+
super
|
72
|
+
@_key = new_key
|
73
|
+
end
|
74
|
+
def key
|
75
|
+
@_key
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
# Defines the methods for a cryptographic hash function.
|
83
|
+
#
|
84
|
+
# digest_class should be an object similar to the classes in the Digest
|
85
|
+
# name-space. Specifically, it should implement the digest method.
|
86
|
+
#
|
87
|
+
# The following methods are defined for a type named 'name':
|
88
|
+
# * name(array | String) -> array
|
89
|
+
# * name_length -> number
|
90
|
+
# * name_digest_class -> Class
|
91
|
+
def crypto_hash(name, digest_class)
|
92
|
+
digest_length = digest_class.digest('').length
|
93
|
+
|
94
|
+
defines = Proc.new do
|
95
|
+
define_method :"#{name}" do |data|
|
96
|
+
data = data.pack 'C*' unless data.kind_of? String
|
97
|
+
digest_class.digest(data).unpack 'C*'
|
98
|
+
end
|
99
|
+
define_method(:"#{name}_digest_class") { digest_class }
|
100
|
+
define_method(:"#{name}_length") { digest_length }
|
101
|
+
end
|
102
|
+
|
103
|
+
@target.class_eval &defines
|
104
|
+
(class << @target; self; end).module_eval &defines
|
105
|
+
end
|
106
|
+
end # class Crypto
|
107
|
+
|
108
|
+
|
109
|
+
# Implementation code for the Crypto methods.
|
110
|
+
module Crypto::Impl
|
111
|
+
def self.key_from_array(array, offset, ssl_class, abi_type)
|
112
|
+
key = ssl_class.new
|
113
|
+
numbers = self.send :"read_#{abi_type}", array, offset
|
114
|
+
numbers.each { |k, v| key.send :"#{k}=", v }
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.key_to_array(key, abi_type)
|
118
|
+
components = self.send :"#{abi_type}_components"
|
119
|
+
numbers = Hash[*(components.map { |c| [c, key.send(c.to_sym) ]}.flatten)]
|
120
|
+
self.send :"to_#{abi_type}", numbers
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end # namespace Tem::Builders
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
|
4
|
+
# :nodoc: namespace
|
5
|
+
module Tem::Builders
|
6
|
+
|
7
|
+
# Builder class for the ISA (Instruction Set Architecture) builder.
|
8
|
+
class Isa
|
9
|
+
# Creates a builder targeting a module / class.
|
10
|
+
#
|
11
|
+
# class_or_module will receive the ISA method definitions. abi should be a
|
12
|
+
# class or module containing the ABI definitions that the ISA definitions
|
13
|
+
# refer to.
|
14
|
+
#
|
15
|
+
# The following options are supported:
|
16
|
+
# opcode_type:: the ABI type encoding the instructions' opcodes (required)
|
17
|
+
def self.define_isa(class_or_module, abi, options) # :yields: isa
|
18
|
+
yield new(class_or_module, abi, options[:opcode_type])
|
19
|
+
end
|
20
|
+
|
21
|
+
# Defines the methods for handling an instruction in the IA.
|
22
|
+
#
|
23
|
+
# The instruction's arguments are provided as an array of hashes. Each hash
|
24
|
+
# describes one argument, and the ordering in the array reflects the encoding
|
25
|
+
# order. The following hash keys are supported:
|
26
|
+
# name:: if defined, the argument can be provided as a named argument;
|
27
|
+
# named arguments must follow positional arguments
|
28
|
+
# type:: the ABI type encoding the argument (required)
|
29
|
+
# reladdr:: if defined, the encoded argument value is relative to the
|
30
|
+
# address of the instruction containing the argument;
|
31
|
+
#
|
32
|
+
# The result of encoding an instruction is a Hash with the following keys:
|
33
|
+
# emit:: the bytes to be emitted into the code stream
|
34
|
+
# link_directives:: an array of directives for the code linker
|
35
|
+
#
|
36
|
+
# Each linker directive refers to an address cell (location in the code
|
37
|
+
# representing an address that the linker must adjust. The following keys can
|
38
|
+
# be present:
|
39
|
+
# type:: the ABI type for the address cell (required)
|
40
|
+
# offset:: the address cell's offset in the emitted bytes (required)
|
41
|
+
# address:: the absolute address to point to (mutually exclusive with label)
|
42
|
+
# label:: the name of a label that the address must point to
|
43
|
+
# relative:: if false, the address cell holds an absolute address;
|
44
|
+
# otherwise, the cell's value is computed as follows:
|
45
|
+
# target address - cell address + value of relative;
|
46
|
+
# (optional, default value is false)
|
47
|
+
# The following methods are defined for a type named 'name':
|
48
|
+
# * encode_name(*arguments) -> Hash
|
49
|
+
def instruction(opcode, name, *iargs)
|
50
|
+
encoded_opcode = @abi.send :"to_#{@opcode_type}", opcode
|
51
|
+
abi = @abi # Capture the ABI in the method closures.
|
52
|
+
named_indexes = {}
|
53
|
+
iargs.map { |iarg| iarg[:name] }.
|
54
|
+
each_with_index { |argname, i| named_indexes[argname] = i if argname }
|
55
|
+
arg_encode_msgs = iargs.map { |iarg| :"to_#{iarg[:type]}" }
|
56
|
+
defines = Proc.new do
|
57
|
+
define_method :"emit_#{name}" do |*args|
|
58
|
+
# Flatten arguments by resolving named parameters to indexes.
|
59
|
+
arg_index = 0
|
60
|
+
fargs = []
|
61
|
+
args.each_with_index do |arg, i|
|
62
|
+
fargs[i] = arg and next unless arg.kind_of? Hash
|
63
|
+
|
64
|
+
if i != args.length - 1
|
65
|
+
raise "Named arguments must follow inline arguments! (arg #{i})"
|
66
|
+
end
|
67
|
+
arg.each do |k, v|
|
68
|
+
raise "#{name} has no #{k} argument" unless i = named_indexes[k]
|
69
|
+
raise "Argument #{k} was already assigned a value" if fargs[i]
|
70
|
+
fargs[i] = v
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
arg_count = fargs.inject(0) { |acc, v| v.nil? ? acc : acc + 1 }
|
75
|
+
if arg_count != iargs.length
|
76
|
+
raise "#{name} requires #{fargs.length} args, given #{arg_count}"
|
77
|
+
end
|
78
|
+
|
79
|
+
# Encode parameters.
|
80
|
+
# @lines[@body.length] = Kernel.caller(0)
|
81
|
+
|
82
|
+
emit = encoded_opcode
|
83
|
+
link_directives = []
|
84
|
+
fargs.each_with_index do |arg, i|
|
85
|
+
if (arg.kind_of? Numeric) && !arg[:reladdr]
|
86
|
+
emit += abi.send arg_encode_msgs[i], arg
|
87
|
+
else
|
88
|
+
link_directive = { :type => iargs[i][:type], :offset => emit.length,
|
89
|
+
:relative => iargs[i][:reladdr] || false }
|
90
|
+
if arg.kind_of? Numeric
|
91
|
+
link_directive[:address] = arg.to_i
|
92
|
+
else
|
93
|
+
link_directive[:label] = arg.to_sym
|
94
|
+
end
|
95
|
+
link_directives << link_directive
|
96
|
+
emit += abi.send arg_encode_msgs[i], 0
|
97
|
+
end
|
98
|
+
end
|
99
|
+
{ :emit => emit, :link_directives => link_directives }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
@target.class_eval &defines
|
104
|
+
(class << @target; self; end).module_eval &defines
|
105
|
+
end
|
106
|
+
|
107
|
+
# The module / class impacted by the builder.
|
108
|
+
attr_reader :target
|
109
|
+
|
110
|
+
# Creates a builder targeting a module / class.
|
111
|
+
def initialize(target, abi, opcode_type)
|
112
|
+
@target = target
|
113
|
+
@target.const_set :Abi, abi
|
114
|
+
@abi = abi
|
115
|
+
@opcode_type = opcode_type
|
116
|
+
end
|
117
|
+
private_class_method :new
|
118
|
+
end # class Isa
|
119
|
+
|
120
|
+
end # namespace Tem::Builders
|