tem_ruby 0.9.0
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 +35 -0
- data/LICENSE +21 -0
- data/Manifest +45 -0
- data/README +6 -0
- data/bin/tem_bench +9 -0
- data/bin/tem_ca +13 -0
- data/bin/tem_irb +18 -0
- data/bin/tem_stat +39 -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 +12 -0
- data/lib/scard/java_card.rb +31 -0
- data/lib/scard/jcop_remote_terminal.rb +52 -0
- data/lib/scard/pcsc_terminal.rb +83 -0
- data/lib/tem/_cert.rb +158 -0
- data/lib/tem/abi.rb +55 -0
- data/lib/tem/buffers.rb +98 -0
- data/lib/tem/ca.rb +114 -0
- data/lib/tem/crypto_abi.rb +216 -0
- data/lib/tem/ecert.rb +78 -0
- data/lib/tem/hive.rb +18 -0
- data/lib/tem/keys.rb +60 -0
- data/lib/tem/lifecycle.rb +8 -0
- data/lib/tem/sec_assembler.rb +91 -0
- data/lib/tem/sec_exec_error.rb +45 -0
- data/lib/tem/sec_opcodes.rb +154 -0
- data/lib/tem/seclosures.rb +82 -0
- data/lib/tem/secpack.rb +86 -0
- data/lib/tem/tag.rb +28 -0
- data/lib/tem/tem.rb +47 -0
- data/lib/tem/toolkit.rb +104 -0
- data/lib/tem_ruby.rb +29 -0
- data/tem_ruby.gemspec +53 -0
- data/test/_test_cert.rb +81 -0
- data/test/test_driver.rb +127 -0
- data/test/test_exceptions.rb +55 -0
- data/test/test_tem.rb +542 -0
- data/timings/blank_bound_secpack.rb +20 -0
- data/timings/blank_sec.rb +15 -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 +66 -0
- data/timings/vm_perf.rb +141 -0
- data/timings/vm_perf_bound.rb +142 -0
- metadata +143 -0
data/test/test_tem.rb
ADDED
@@ -0,0 +1,542 @@
|
|
1
|
+
require 'tem_ruby'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TemTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@terminal = Tem::SCard::JCOPRemoteTerminal.new
|
7
|
+
unless @terminal.connect
|
8
|
+
@terminal.disconnect
|
9
|
+
@terminal = Tem::SCard::PCSCTerminal.new
|
10
|
+
@terminal.connect
|
11
|
+
end
|
12
|
+
@javacard = Tem::SCard::JavaCard.new(@terminal)
|
13
|
+
@tem = Tem::Session.new(@javacard)
|
14
|
+
|
15
|
+
@tem.kill
|
16
|
+
@tem.activate
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
@terminal.disconnect unless @terminal.nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_alu
|
24
|
+
proc = @tem.assemble { |s|
|
25
|
+
s.ldbc 10
|
26
|
+
s.outnew
|
27
|
+
s.ldwc 0x1234
|
28
|
+
s.ldwc 0x5678
|
29
|
+
s.dupn :n => 2
|
30
|
+
s.add
|
31
|
+
s.outw
|
32
|
+
s.sub
|
33
|
+
s.outw
|
34
|
+
s.ldwc 0x0155
|
35
|
+
s.ldwc 0x02AA
|
36
|
+
s.mul
|
37
|
+
s.outw
|
38
|
+
s.ldwc 0x390C
|
39
|
+
s.ldwc 0x00AA
|
40
|
+
s.dupn :n => 2
|
41
|
+
s.div
|
42
|
+
s.outw
|
43
|
+
s.mod
|
44
|
+
s.outw
|
45
|
+
s.halt
|
46
|
+
s.extra 10
|
47
|
+
}
|
48
|
+
result = @tem.execute proc
|
49
|
+
assert_equal [0x68, 0xAC, 0xBB, 0xBC, 0x8C, 0x72, 0x00, 0x55, 0x00, 0x9A],
|
50
|
+
result, 'the ALU isn\'t working well'
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_memory
|
54
|
+
proc = @tem.assemble { |s|
|
55
|
+
s.label :clobber
|
56
|
+
s.ldbc 32
|
57
|
+
s.label :clobber2
|
58
|
+
s.outnew
|
59
|
+
s.ldwc 0x55AA
|
60
|
+
s.stw :clobber
|
61
|
+
s.ldb :clobber
|
62
|
+
s.outw
|
63
|
+
s.ldw :clobber
|
64
|
+
s.outw
|
65
|
+
s.ldbc 0xA5 - (1 << 8)
|
66
|
+
s.stb :clobber
|
67
|
+
s.ldw :clobber
|
68
|
+
s.outw
|
69
|
+
s.ldwc :clobber2
|
70
|
+
s.dupn :n => 1
|
71
|
+
s.dupn :n => 2
|
72
|
+
s.ldwc 0x9966 - (1 << 16)
|
73
|
+
s.stwv
|
74
|
+
s.ldbv
|
75
|
+
s.outw
|
76
|
+
s.ldbc 0x98 - (1 << 8)
|
77
|
+
s.stbv
|
78
|
+
s.ldwv
|
79
|
+
s.outw
|
80
|
+
s.ldwc 0x1122
|
81
|
+
s.ldwc 0x3344
|
82
|
+
s.ldwc 0x5566
|
83
|
+
s.flipn :n => 3
|
84
|
+
s.outw
|
85
|
+
s.outw
|
86
|
+
s.outw
|
87
|
+
s.halt
|
88
|
+
s.stack
|
89
|
+
s.extra 10
|
90
|
+
}
|
91
|
+
result = @tem.execute proc
|
92
|
+
assert_equal [0x00, 0x55, 0x55, 0xAA, 0xA5, 0xAA, 0xFF, 0x99, 0x98, 0x66, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66],
|
93
|
+
result, 'the memory unit isn\'t working well'
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_output
|
97
|
+
proc = @tem.assemble { |s|
|
98
|
+
s.ldbc 32
|
99
|
+
s.outnew
|
100
|
+
s.outfxb :size => 3, :from => :area1
|
101
|
+
s.ldbc 5
|
102
|
+
s.outvlb :from => :area2
|
103
|
+
s.ldbc 4
|
104
|
+
s.ldwc :area3
|
105
|
+
s.outvb
|
106
|
+
s.ldwc 0x99AA - (1 << 16)
|
107
|
+
s.ldwc 0xFA55 - (1 << 16)
|
108
|
+
s.outb
|
109
|
+
s.outw
|
110
|
+
s.halt
|
111
|
+
s.label :area1
|
112
|
+
s.immed :ubyte, [0xFE, 0xCD, 0x9A]
|
113
|
+
s.label :area2
|
114
|
+
s.immed :ubyte, [0xAB, 0x95, 0xCE, 0xFD, 0x81]
|
115
|
+
s.label :area3
|
116
|
+
s.immed :ubyte, [0xEC, 0xDE, 0xAD, 0xCF]
|
117
|
+
s.stack
|
118
|
+
s.extra 10
|
119
|
+
}
|
120
|
+
result = @tem.execute proc
|
121
|
+
assert_equal [0xFE, 0xCD, 0x9A, 0xAB, 0x95, 0xCE, 0xFD, 0x81, 0xEC, 0xDE, 0xAD, 0xCF, 0x55, 0x99, 0xAA],
|
122
|
+
result, 'the output unit isn\'t working well'
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_branching
|
126
|
+
secpack = @tem.assemble { |s|
|
127
|
+
s.ldbc 24
|
128
|
+
s.outnew
|
129
|
+
|
130
|
+
s.jmp :to => :over_halt
|
131
|
+
s.halt # this gets jumped over
|
132
|
+
s.label :over_halt
|
133
|
+
s.ldbc 4
|
134
|
+
s.label :test_loop
|
135
|
+
s.dupn :n => 1
|
136
|
+
s.outb
|
137
|
+
s.ldbc 1
|
138
|
+
s.sub
|
139
|
+
s.dupn :n=> 1
|
140
|
+
s.jae :to => :test_loop
|
141
|
+
|
142
|
+
failed = 0xFA - (1 << 8)
|
143
|
+
[
|
144
|
+
[:ja, [1, 1, failed], [0, failed, 2], [-1, failed, 3]],
|
145
|
+
[:jae, [1, 4, failed], [0, 5, failed], [-1, failed, 6]],
|
146
|
+
[:jb, [1, failed, 7], [0, failed, 8], [-1, 9, failed]],
|
147
|
+
[:jbe, [1, failed, 10], [0, 11, failed], [-1, 12, failed]],
|
148
|
+
[:jz, [1, failed, 13], [0, 14, failed], [-1, failed, 15]],
|
149
|
+
[:jne, [1, 16, failed], [0, failed, 17], [-1, 18, failed]],
|
150
|
+
].each do |op_line|
|
151
|
+
op = op_line.shift
|
152
|
+
op_line.each_index do |i|
|
153
|
+
then_label = "#{op}_l#{i}_t".to_sym
|
154
|
+
out_label = "#{op}_l#{i}_o".to_sym
|
155
|
+
|
156
|
+
s.ldbc op_line[i][0]
|
157
|
+
s.send op, :to => then_label
|
158
|
+
s.ldbc op_line[i][2]
|
159
|
+
s.jmp :to => out_label
|
160
|
+
s.label then_label
|
161
|
+
s.ldbc op_line[i][1]
|
162
|
+
s.label out_label
|
163
|
+
s.outb
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
s.halt
|
168
|
+
s.extra 10
|
169
|
+
}
|
170
|
+
result = @tem.execute secpack
|
171
|
+
assert_equal [0x04, 0x03, 0x02, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04,
|
172
|
+
0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12],
|
173
|
+
result, 'the branching unit isn\'t working well'
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_memory_copy_compare(yaml_roundtrip = false)
|
177
|
+
sec = @tem.assemble { |s|
|
178
|
+
s.ldwc :const => 16
|
179
|
+
s.outnew
|
180
|
+
s.ldwc :const => 6
|
181
|
+
s.ldwc :cmp_med
|
182
|
+
s.ldwc :cmp_lo
|
183
|
+
s.mcmpvb
|
184
|
+
s.outw
|
185
|
+
s.mcmpfxb :size => 6, :op1 => :cmp_med, :op2 => :cmp_hi
|
186
|
+
s.outw
|
187
|
+
s.ldwc :const => 4
|
188
|
+
s.ldwc :cmp_lo
|
189
|
+
s.ldwc :cmp_med
|
190
|
+
s.mcmpvb
|
191
|
+
s.outw
|
192
|
+
|
193
|
+
s.mcfxb :size => 6, :from => :cmp_hi, :to => :copy_buf
|
194
|
+
s.pop
|
195
|
+
s.outfxb :size => 6, :from => :copy_buf
|
196
|
+
s.ldwc :const => 4
|
197
|
+
s.ldwc :cmp_hi
|
198
|
+
s.ldwc :copy_buf2
|
199
|
+
s.mcvb
|
200
|
+
s.pop
|
201
|
+
s.outfxb :size => 4, :from => :copy_buf2
|
202
|
+
|
203
|
+
s.halt
|
204
|
+
s.label :cmp_lo
|
205
|
+
s.immed :ubyte, [0xA3, 0x2C, 0x51, 0x63, 0x2C, 0x12]
|
206
|
+
s.label :cmp_med
|
207
|
+
s.immed :ubyte, [0xA3, 0x2C, 0x51, 0x63, 0x2D, 0x11]
|
208
|
+
s.label :cmp_hi
|
209
|
+
s.immed :ubyte, [0xA3, 0x2C, 0x51, 0x63, 0x2E, 0x10]
|
210
|
+
s.label :cmp_hi2
|
211
|
+
s.immed :ubyte, [0xA3, 0x2C, 0x51, 0x63, 0x2E, 0x10]
|
212
|
+
s.label :copy_buf
|
213
|
+
s.filler :ubyte, 6
|
214
|
+
s.label :copy_buf2
|
215
|
+
s.filler :ubyte, 4
|
216
|
+
s.stack
|
217
|
+
s.extra 10
|
218
|
+
}
|
219
|
+
|
220
|
+
if yaml_roundtrip
|
221
|
+
# same test, except the SECpack is serialized/deserialized
|
222
|
+
yaml_sec = sec.to_yaml_str
|
223
|
+
sec = Tem::SecPack.new_from_yaml_str(yaml_sec)
|
224
|
+
end
|
225
|
+
result = @tem.execute sec
|
226
|
+
assert_equal [0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0xA3, 0x2C, 0x51, 0x63, 0x2E, 0x10, 0xA3, 0x2C, 0x51, 0x63],
|
227
|
+
result, 'memory copy/compare isn\'t working well'
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_crypto_hash
|
231
|
+
garbage1 = (0...8).map { |x| (31 * x * x + 5 * x + 3) % 256 }
|
232
|
+
garbage2 = (0...11).map { |x| (69 * x * x + 62 * x + 10) % 256 }
|
233
|
+
hash_size = 20
|
234
|
+
|
235
|
+
proc = @tem.assemble { |s|
|
236
|
+
s.ldwc hash_size * 3
|
237
|
+
s.outnew
|
238
|
+
s.mdfxb :size => garbage1.length, :from => :garbage1, :to => :hash_area
|
239
|
+
s.outfxb :size => hash_size, :from => :hash_area
|
240
|
+
s.mdfxb :size => garbage2.length, :from => :garbage2, :to => 0xFFFF
|
241
|
+
s.ldwc garbage2.length
|
242
|
+
s.ldwc :garbage2
|
243
|
+
s.ldwc :hash_area
|
244
|
+
s.mdvb
|
245
|
+
s.outfxb :size => hash_size, :from => :hash_area
|
246
|
+
s.halt
|
247
|
+
s.label :garbage1
|
248
|
+
s.immed :ubyte, garbage1
|
249
|
+
s.label :garbage2
|
250
|
+
s.immed :ubyte, garbage2
|
251
|
+
s.label :hash_area
|
252
|
+
s.filler :ubyte, hash_size
|
253
|
+
s.stack
|
254
|
+
s.extra 10
|
255
|
+
}
|
256
|
+
|
257
|
+
result = @tem.execute proc
|
258
|
+
assert_equal [garbage1, garbage2, garbage2].map { |d| @tem.hash_for_tem d}.flatten,
|
259
|
+
result, 'cryptographic hashing isn\'t working well'
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_crypto_pstore
|
263
|
+
key1 = (0...(@tem.tem_ps_key_length)).map { |x| (61 * x * x + 62 * x + 10) % 256 }
|
264
|
+
key2 = key1.dup; key2[key2.length - 1] += 1
|
265
|
+
random_value = (0...(@tem.tem_ps_value_length)).map { |x| (69 * x * x + 62 * x + 10) % 256 }
|
266
|
+
|
267
|
+
sec = @tem.assemble { |s|
|
268
|
+
s.ldwc 3 * @tem.tem_ushort_length + @tem.tem_ps_value_length * 2
|
269
|
+
s.outnew
|
270
|
+
|
271
|
+
# check that the location is blank
|
272
|
+
s.ldwc :pstore_key
|
273
|
+
s.pshkvb
|
274
|
+
s.outw
|
275
|
+
|
276
|
+
# write to create the location
|
277
|
+
s.pswrfxb :key => :pstore_key, :from => :s_value
|
278
|
+
# check that the location isn't blank anymore
|
279
|
+
s.pshkfxb :key => :pstore_key
|
280
|
+
s.outw
|
281
|
+
# re-read (should get what was written)
|
282
|
+
s.ldwc :pstore_key
|
283
|
+
s.ldwc :s_value2
|
284
|
+
s.psrdvb
|
285
|
+
s.ldwc :s_value2
|
286
|
+
s.outvb
|
287
|
+
|
288
|
+
# drop the location
|
289
|
+
s.ldwc :pstore_key
|
290
|
+
s.dupn :n => 1
|
291
|
+
s.psrm
|
292
|
+
# check that the location is blank again
|
293
|
+
s.pshkvb
|
294
|
+
s.outw
|
295
|
+
|
296
|
+
s.halt
|
297
|
+
|
298
|
+
s.label :pstore_key
|
299
|
+
s.immed :ubyte, key1
|
300
|
+
s.label :s_value
|
301
|
+
s.immed :ubyte, random_value
|
302
|
+
s.label :s_value2
|
303
|
+
s.filler :ps_value
|
304
|
+
s.stack
|
305
|
+
s.extra 16
|
306
|
+
}
|
307
|
+
expected = @tem.to_tem_ushort(0) + @tem.to_tem_ushort(1) + random_value + @tem.to_tem_ushort(0)
|
308
|
+
result = @tem.execute sec
|
309
|
+
assert_equal expected, result, 'persistent store locations aren\'t working well'
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_crypto_random
|
313
|
+
sec = @tem.assemble { |s|
|
314
|
+
s.ldbc 16
|
315
|
+
s.outnew
|
316
|
+
s.ldbc 8
|
317
|
+
s.dupn :n => 1
|
318
|
+
s.ldwc :rnd_area
|
319
|
+
s.dupn :n => 2
|
320
|
+
s.rnd
|
321
|
+
s.outvb
|
322
|
+
s.ldbc(-1)
|
323
|
+
s.rnd
|
324
|
+
s.halt
|
325
|
+
s.label :rnd_area
|
326
|
+
s.filler :ubyte, 8
|
327
|
+
s.stack
|
328
|
+
s.extra 10
|
329
|
+
}
|
330
|
+
|
331
|
+
result = @tem.execute sec
|
332
|
+
assert_equal 16, result.length, 'monotonic counters aren\'t working well'
|
333
|
+
end
|
334
|
+
|
335
|
+
def i_crypt(data, key_id, authz, mode = :encrypt, direct_io = true, max_output = nil)
|
336
|
+
if max_output.nil?
|
337
|
+
max_output = case mode
|
338
|
+
when :encrypt
|
339
|
+
((data.length + 239) / 240) * 256
|
340
|
+
when :decrypt
|
341
|
+
data.length
|
342
|
+
when :sign
|
343
|
+
256
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
crypt_opcode = {:encrypt => :kefxb, :decrypt => :kdfxb, :sign => :ksfxb}[mode]
|
348
|
+
ex_sec = @tem.assemble { |s|
|
349
|
+
# buffer
|
350
|
+
s.ldwc :const => max_output
|
351
|
+
s.outnew
|
352
|
+
s.ldbc :const => key_id
|
353
|
+
s.authk :auth => :key_auth
|
354
|
+
s.send crypt_opcode, :from => :data, :size => data.length, :to => (direct_io ? 0xFFFF : :outdata)
|
355
|
+
s.outvlb :from => :outdata unless direct_io
|
356
|
+
s.halt
|
357
|
+
|
358
|
+
s.label :key_auth
|
359
|
+
s.immed :ubyte, authz
|
360
|
+
s.label :data
|
361
|
+
s.immed :ubyte, data
|
362
|
+
unless direct_io
|
363
|
+
s.label :outdata
|
364
|
+
s.filler :ubyte, max_output
|
365
|
+
end
|
366
|
+
s.stack
|
367
|
+
s.extra 10
|
368
|
+
}
|
369
|
+
return @tem.execute(ex_sec)
|
370
|
+
end
|
371
|
+
|
372
|
+
def i_verify(data, signature, key_id, authz)
|
373
|
+
sign_sec = @tem.assemble { |s|
|
374
|
+
# buffer
|
375
|
+
s.ldbc :const => 1
|
376
|
+
s.outnew
|
377
|
+
s.ldbc :const => key_id
|
378
|
+
s.authk :auth => :key_auth
|
379
|
+
s.kvsfxb :from => :data, :size => data.length, :signature => :signature
|
380
|
+
s.outb
|
381
|
+
s.halt
|
382
|
+
|
383
|
+
s.label :key_auth
|
384
|
+
s.immed :ubyte, authz
|
385
|
+
s.label :data
|
386
|
+
s.immed :ubyte, data
|
387
|
+
s.label :signature
|
388
|
+
s.immed :ubyte, signature
|
389
|
+
s.stack
|
390
|
+
s.extra 10
|
391
|
+
}
|
392
|
+
return @tem.execute(sign_sec)[0] == 1
|
393
|
+
end
|
394
|
+
|
395
|
+
def i_test_crypto_pki_ops(pubk_id, privk_id, pubk, privk, authz)
|
396
|
+
garbage = (1...569).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
|
397
|
+
|
398
|
+
# SEC/priv-sign + CPU/pub-verify, direct IO
|
399
|
+
signed_garbage = i_crypt(garbage, privk_id, authz, :sign, true)
|
400
|
+
assert privk.verify(garbage, signed_garbage), 'SEC priv-signing + CPU pub-verify failed on good data'
|
401
|
+
|
402
|
+
# SEC/priv-sign + CPU/pub-verify, indirect IO
|
403
|
+
signed_garbage = i_crypt(garbage, privk_id, authz, :sign, false)
|
404
|
+
assert privk.verify(garbage, signed_garbage), 'SEC priv-signing + CPU pub-verify failed on good data'
|
405
|
+
|
406
|
+
# CPU/priv-sign + SEC/pub-verify
|
407
|
+
signed_garbage = privk.sign garbage
|
408
|
+
assert i_verify(garbage, signed_garbage, pubk_id, authz), 'CPU priv-signing + SEC pub-verify failed on good data'
|
409
|
+
|
410
|
+
# CPU/priv-encrypt + SEC/pub-decrypt, indirect IO
|
411
|
+
encrypted_garbage = privk.encrypt garbage
|
412
|
+
decrypted_garbage = i_crypt(encrypted_garbage, pubk_id, authz, :decrypt, false)
|
413
|
+
assert_equal garbage, decrypted_garbage, 'SEC priv-encryption + CPU pub-decryption messed up the data'
|
414
|
+
|
415
|
+
# SEC/pub-encrypt + CPU/priv-decrypt, indirect IO
|
416
|
+
encrypted_garbage = i_crypt(garbage, pubk_id, authz, :encrypt, false)
|
417
|
+
decrypted_garbage = privk.decrypt encrypted_garbage
|
418
|
+
assert_equal garbage, decrypted_garbage, 'SEC priv-encryption + CPU pub-decryption messed up the data'
|
419
|
+
|
420
|
+
# CPU/pub-encrypt + SEC/priv-decrypt, direct-IO
|
421
|
+
encrypted_garbage = pubk.encrypt garbage
|
422
|
+
decrypted_garbage = i_crypt(encrypted_garbage, privk_id, authz, :decrypt, true)
|
423
|
+
assert_equal garbage, decrypted_garbage, 'CPU pub-encryption + SEC priv-decryption messed up the data'
|
424
|
+
|
425
|
+
# SEC/priv-encrypt + CPU/pub-decrypt, direct-IO
|
426
|
+
encrypted_garbage = i_crypt(garbage, privk_id, authz, :encrypt, true)
|
427
|
+
decrypted_garbage = pubk.decrypt encrypted_garbage
|
428
|
+
assert_equal garbage, decrypted_garbage, 'SEC priv-encryption + CPU pub-decryption messed up the data'
|
429
|
+
end
|
430
|
+
|
431
|
+
def test_crypto_pki
|
432
|
+
# crypto run with an internally generated key
|
433
|
+
keyd = @tem.tk_gen_key :asymmetric
|
434
|
+
pubk = @tem.tk_read_key keyd[:pubk_id], keyd[:authz]
|
435
|
+
privk = @tem.tk_read_key keyd[:privk_id], keyd[:authz]
|
436
|
+
i_test_crypto_pki_ops(keyd[:pubk_id], keyd[:privk_id], pubk, privk, keyd[:authz])
|
437
|
+
|
438
|
+
# crypto run with an externally generated key
|
439
|
+
ekey = OpenSSL::PKey::RSA.generate(2048, 65537)
|
440
|
+
pubk = @tem.new_key_from_ssl ekey, true
|
441
|
+
privk = @tem.new_key_from_ssl ekey, false
|
442
|
+
pubk_id = @tem.tk_post_key pubk, keyd[:authz]
|
443
|
+
privk_id = @tem.tk_post_key privk, keyd[:authz]
|
444
|
+
i_test_crypto_pki_ops(pubk_id, privk_id, pubk, privk, keyd[:authz])
|
445
|
+
end
|
446
|
+
|
447
|
+
def test_crypted_secpack(yaml_roundtrip = false)
|
448
|
+
keyd = @tem.tk_gen_key
|
449
|
+
pubk = @tem.tk_read_key keyd[:pubk_id], keyd[:authz]
|
450
|
+
|
451
|
+
secret = (0...16).map { |i| (99 * i * i + 51 * i + 33) % 256 }
|
452
|
+
sealed_sec = @tem.assemble { |s|
|
453
|
+
s.ldbc secret.length
|
454
|
+
s.outnew
|
455
|
+
s.label :mess_place
|
456
|
+
s.outfxb :size => secret.length, :from => :secret
|
457
|
+
s.halt
|
458
|
+
s.label :secret
|
459
|
+
s.immed :ubyte, secret
|
460
|
+
s.label :plain
|
461
|
+
s.stack
|
462
|
+
s.extra 8
|
463
|
+
}
|
464
|
+
|
465
|
+
sb = sealed_sec.body
|
466
|
+
secret_found = false
|
467
|
+
0.upto(sb.length - 1) { |i| if secret == sb[i, secret.length] then secret_found = true; break; end }
|
468
|
+
assert secret_found, 'test_crypted_secpack needs rethinking: the raw sec does not contain the secret'
|
469
|
+
|
470
|
+
sealed_sec.seal pubk, :secret, :plain
|
471
|
+
if yaml_roundtrip
|
472
|
+
# same test, except the SECpack is serialized/deserialized
|
473
|
+
yaml_sealed_sec = sealed_sec.to_yaml_str
|
474
|
+
sealed_sec = Tem::SecPack.new_from_yaml_str(yaml_sealed_sec)
|
475
|
+
end
|
476
|
+
result = @tem.execute sealed_sec, keyd[:privk_id]
|
477
|
+
assert_equal secret, result, 'TEM failed to decrypt secpack'
|
478
|
+
|
479
|
+
sb = sealed_sec.body
|
480
|
+
0.upto(sb.length - 1) { |i| assert_not_equal secret, sb[i, secret.length], 'secret found unencrypted in sealed sec' }
|
481
|
+
|
482
|
+
sealed_sec.body[sealed_sec.label_address(:mess_place)] += 1
|
483
|
+
assert_raise(RuntimeError, 'secpack validation isn\'t working') { @tem.execute sealed_sec }
|
484
|
+
end
|
485
|
+
|
486
|
+
def test_yaml_secpack
|
487
|
+
# simple test to ensure that the body is preserved
|
488
|
+
sec = @tem.assemble { |s|
|
489
|
+
s.ldbc 10
|
490
|
+
s.outnew
|
491
|
+
s.ldwc 0x1234
|
492
|
+
s.ldwc 0x5678
|
493
|
+
s.dupn :n => 2
|
494
|
+
s.add
|
495
|
+
s.outw
|
496
|
+
s.sub
|
497
|
+
s.outw
|
498
|
+
s.ldwc 0x0155
|
499
|
+
s.ldwc 0x02AA
|
500
|
+
s.mul
|
501
|
+
s.outw
|
502
|
+
s.ldwc 0x390C
|
503
|
+
s.ldwc 0x00AA
|
504
|
+
s.dupn :n => 2
|
505
|
+
s.div
|
506
|
+
s.outw
|
507
|
+
s.mod
|
508
|
+
s.outw
|
509
|
+
s.halt
|
510
|
+
s.stack
|
511
|
+
s.extra 10
|
512
|
+
}
|
513
|
+
yaml_sec = sec.to_yaml_str
|
514
|
+
sec2 = Tem::SecPack.new_from_yaml_str(yaml_sec)
|
515
|
+
assert_equal sec.body, sec2.body, 'SECpack body corrupted during serialization'
|
516
|
+
|
517
|
+
# re-run the memory test (reasonably large SECpack) to ensure that de-serialized SECpacks are equivalent to the originals
|
518
|
+
test_memory_copy_compare(true)
|
519
|
+
# re-run the memory test (reasonably large SECpack) to ensure that serialization works on sealed SECpacks
|
520
|
+
test_crypted_secpack(true)
|
521
|
+
end
|
522
|
+
|
523
|
+
def test_emit
|
524
|
+
# try to emit
|
525
|
+
er = @tem.emit
|
526
|
+
assert er != nil, 'TEM emitting failed'
|
527
|
+
|
528
|
+
# now verify that the private key is good and the authorization matches
|
529
|
+
privek = @tem.tk_read_key 0, er[:privek_auth]
|
530
|
+
assert((not privek.is_public?), 'TEM emission failed to produce a proper PrivEK')
|
531
|
+
|
532
|
+
# verify that the public key can be read from the ECert
|
533
|
+
pubek = @tem.pubek
|
534
|
+
assert pubek.is_public?, 'TEM emission failed to produce a proper PubEK'
|
535
|
+
|
536
|
+
# verify the PrivEK against the ECert
|
537
|
+
ecert = @tem.endorsement_cert
|
538
|
+
ecert.verify privek.ssl_key
|
539
|
+
|
540
|
+
@tem.tk_delete_key 0, er[:privek_auth]
|
541
|
+
end
|
542
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class TemTimings
|
2
|
+
def time_blank_bound_secpack
|
3
|
+
secpack = @tem.assemble { |s|
|
4
|
+
s.ldbc 0
|
5
|
+
s.outnew
|
6
|
+
s.halt
|
7
|
+
s.label :secret
|
8
|
+
s.filler :ubyte, 50
|
9
|
+
s.label :plain
|
10
|
+
s.filler :ubyte, 220
|
11
|
+
s.stack
|
12
|
+
s.extra 2
|
13
|
+
}
|
14
|
+
secpack.seal @tem.pubek, :secret, :plain
|
15
|
+
|
16
|
+
print "SECpack has #{secpack.body.length} bytes, runs 3 instructions and produces 0 bytes\n"
|
17
|
+
do_timing { @tem.execute secpack }
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class TemTimings
|
2
|
+
def time_blank_sec
|
3
|
+
secpack = @tem.assemble { |s|
|
4
|
+
s.ldbc 0
|
5
|
+
s.outnew
|
6
|
+
s.halt
|
7
|
+
s.filler :ubyte, 70
|
8
|
+
s.stack
|
9
|
+
s.extra 2
|
10
|
+
}
|
11
|
+
|
12
|
+
print "SECpack has #{secpack.body.length} bytes, runs 3 instructions and produces 0 bytes\n"
|
13
|
+
do_timing { @tem.execute secpack }
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class TemTimings
|
2
|
+
def time_devchip_decrypt
|
3
|
+
pubek = @tem.pubek
|
4
|
+
data = (1...120).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
|
5
|
+
encrypted_data = pubek.encrypt data
|
6
|
+
print "Encrypted blob has #{encrypted_data.length} bytes\n"
|
7
|
+
do_timing { @tem.devchip_decrypt encrypted_data, 0 }
|
8
|
+
end
|
9
|
+
end
|
data/timings/timings.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'tem_ruby'
|
2
|
+
|
3
|
+
require 'timings/blank_bound_secpack.rb'
|
4
|
+
require 'timings/blank_sec.rb'
|
5
|
+
require 'timings/devchip_decrypt.rb'
|
6
|
+
require 'timings/post_buffer.rb'
|
7
|
+
require 'timings/simple_apdu.rb'
|
8
|
+
require 'timings/vm_perf.rb'
|
9
|
+
require 'timings/vm_perf_bound.rb'
|
10
|
+
|
11
|
+
class TemTimings
|
12
|
+
def setup
|
13
|
+
@terminal = Tem::SCard::JCOPRemoteTerminal.new
|
14
|
+
unless @terminal.connect
|
15
|
+
@terminal.disconnect
|
16
|
+
@terminal = Tem::SCard::PCSCTerminal.new
|
17
|
+
@terminal.connect
|
18
|
+
end
|
19
|
+
@javacard = Tem::SCard::JavaCard.new(@terminal)
|
20
|
+
@tem = Tem::Session.new(@javacard)
|
21
|
+
|
22
|
+
@tem.kill
|
23
|
+
@tem.activate
|
24
|
+
@tem.emit
|
25
|
+
end
|
26
|
+
|
27
|
+
def teardown
|
28
|
+
@tem.kill
|
29
|
+
@terminal.disconnect unless @terminal.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
def do_timing
|
33
|
+
@tem.flush_buffers
|
34
|
+
|
35
|
+
n = 10
|
36
|
+
loop do
|
37
|
+
timings = (0...3).map do |i|
|
38
|
+
t_start = Time.now
|
39
|
+
n.times do
|
40
|
+
yield
|
41
|
+
end
|
42
|
+
t_delta = Time.now - t_start
|
43
|
+
end
|
44
|
+
avg_time = timings.inject { |a,v| a + v } / timings.length
|
45
|
+
max_diff = timings.map { |t| (t - avg_time).abs }.max
|
46
|
+
print "%8d: %3.8fs per run, %3.8fs uncertainty (%2.5f%%)\n" % [n, avg_time / n, max_diff / n, 100 * max_diff / avg_time]
|
47
|
+
|
48
|
+
return avg_time unless max_diff / avg_time >= 0.01
|
49
|
+
n *= 2
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.all_timings
|
54
|
+
t = TemTimings.new
|
55
|
+
t.setup
|
56
|
+
t.methods.select { |m| m =~ /time_/ }.each do |m|
|
57
|
+
print "Timing: #{m[5..-1]}...\n"
|
58
|
+
t.send m.to_sym
|
59
|
+
end
|
60
|
+
t.teardown
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
if __FILE__ == $0
|
65
|
+
TemTimings.all_timings
|
66
|
+
end
|