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
@@ -0,0 +1,45 @@
|
|
1
|
+
# raised when executing a SEC
|
2
|
+
class Tem::SecExecError < StandardError
|
3
|
+
attr_reader :buffer_state, :key_state
|
4
|
+
attr_reader :trace
|
5
|
+
|
6
|
+
def initialize(backtrace, tem_trace, buffer_state, key_state)
|
7
|
+
super 'SEC execution failed on the TEM'
|
8
|
+
set_backtrace backtrace
|
9
|
+
@trace = tem_trace
|
10
|
+
@buffer_state = buffer_state
|
11
|
+
@key_state = key_state
|
12
|
+
end
|
13
|
+
|
14
|
+
def bstat_str
|
15
|
+
if @buffer_state.nil?
|
16
|
+
"no buffer state available"
|
17
|
+
else
|
18
|
+
@buffer_state.inspect
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def kstat_str
|
23
|
+
if @key_state.nil?
|
24
|
+
"no key state available"
|
25
|
+
else
|
26
|
+
@key_state.inspect
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def trace_str
|
31
|
+
if @trace.nil?
|
32
|
+
"no trace available"
|
33
|
+
else
|
34
|
+
"ip=#{'%04x' % @trace[:ip]} sp=#{'%04x' % @trace[:sp]} out=#{'%04x' % @trace[:out]} pscell=#{'%04x' % @trace[:pscell]}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
"SECpack execution generated an exception on the TEM\nTEM Trace: " + trace_str + "\nTEM Buffer Status:\n" + bstat_str + "\nTEM Key Status:\n" + kstat_str
|
40
|
+
end
|
41
|
+
|
42
|
+
def inspect
|
43
|
+
trace_str + "\n" + bstat_str + "\n" + kstat_str
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
class Tem::SecAssembler
|
2
|
+
# 2 ST -> 1 ST
|
3
|
+
opcode :add, 0x10
|
4
|
+
# 2 ST -> 1 ST
|
5
|
+
opcode :sub, 0x11
|
6
|
+
# 2 ST -> 1 ST
|
7
|
+
opcode :mul, 0x12
|
8
|
+
# 2 ST -> 1 ST
|
9
|
+
opcode :div, 0x13
|
10
|
+
# 2 ST -> 1 ST
|
11
|
+
opcode :mod, 0x14
|
12
|
+
# 2 ST -> 1 ST
|
13
|
+
opcode :rnd, 0x1E
|
14
|
+
|
15
|
+
|
16
|
+
# 2 ST -> 1 ST
|
17
|
+
opcode :stbv, 0x3A
|
18
|
+
# 2 ST -> 1 ST
|
19
|
+
opcode :stwv, 0x3B
|
20
|
+
|
21
|
+
# 2 ST -> 1 ST
|
22
|
+
opcode :stk, 0x5B
|
23
|
+
|
24
|
+
|
25
|
+
# 1 ST, 1 IM -> 1 ST
|
26
|
+
opcode :stb , 0x38, {:name => :to, :type => :ushort}
|
27
|
+
# 1 ST, 1 IM -> 1 ST
|
28
|
+
opcode :stw , 0x39, {:name => :to, :type => :ushort}
|
29
|
+
|
30
|
+
|
31
|
+
# 2 IM -> 1 ST
|
32
|
+
opcode(:psupfxb, 0x48, {:name => :key, :type => :ushort}, {:name => :from, :type => :ushort})
|
33
|
+
# 2 ST -> 1 ST
|
34
|
+
opcode :psupvb, 0x49
|
35
|
+
# 2 IM -> 1 ST
|
36
|
+
opcode(:pswrfxb, 0x4A, {:name => :key, :type => :ushort}, {:name => :from, :type => :ushort})
|
37
|
+
# 2 ST -> 1 ST
|
38
|
+
opcode :pswrvb, 0x4B
|
39
|
+
# 2 IM -> 1 ST
|
40
|
+
opcode(:psrdfxb, 0x4C, {:name => :key, :type => :ushort}, {:name => :to, :type => :ushort})
|
41
|
+
# 2 ST -> 1 ST
|
42
|
+
opcode :psrdvb, 0x4D
|
43
|
+
# 2 IM -> 1 ST
|
44
|
+
opcode :pshkfxb, 0x4E, {:name => :key, :type => :ushort}
|
45
|
+
# 2 ST -> 1 ST
|
46
|
+
opcode :pshkvb, 0x4F
|
47
|
+
|
48
|
+
|
49
|
+
# 3 IM -> 1 ST
|
50
|
+
opcode(:mdfxb, 0x18, {:name => :size, :type => :ushort}, {:name => :from, :type => :ushort}, {:name => :to, :type => :ushort})
|
51
|
+
# 3 ST -> 1 ST
|
52
|
+
opcode :mdvb, 0x19
|
53
|
+
# 3 IM -> 1 ST
|
54
|
+
opcode(:mcmpfxb,0x1A, {:name => :size, :type => :ushort}, {:name => :op1, :type => :ushort}, {:name => :op2, :type => :ushort})
|
55
|
+
# 3 ST -> 1 ST
|
56
|
+
opcode :mcmpvb, 0x1B
|
57
|
+
# 3 IM -> 1 ST
|
58
|
+
opcode(:mcfxb, 0x1C, {:name => :size, :type => :ushort}, {:name => :from, :type => :ushort}, {:name => :to, :type => :ushort})
|
59
|
+
# 3 ST -> 1 ST
|
60
|
+
opcode :mcvb, 0x1D
|
61
|
+
|
62
|
+
# 1 ST, 3 IM -> 1 ST
|
63
|
+
opcode(:kefxb, 0x50, {:name => :size, :type => :ushort}, {:name => :from, :type => :ushort}, {:name => :to, :type => :ushort})
|
64
|
+
# 4 ST -> 1 ST
|
65
|
+
opcode :kevb, 0x51
|
66
|
+
# 1 ST, 3 IM -> 1 ST
|
67
|
+
opcode(:kdfxb, 0x52, {:name => :size, :type => :ushort}, {:name => :from, :type => :ushort}, {:name => :to, :type => :ushort})
|
68
|
+
# 4 ST -> 1 ST
|
69
|
+
opcode :kdvb, 0x53
|
70
|
+
# 1 ST, 3 IM -> 1 ST
|
71
|
+
opcode(:ksfxb, 0x54, {:name => :size, :type => :ushort}, {:name => :from, :type => :ushort}, {:name => :to, :type => :ushort})
|
72
|
+
# 4 ST -> 1 ST
|
73
|
+
opcode :ksvb, 0x55
|
74
|
+
# 1 ST, 3 IM -> 1 ST
|
75
|
+
opcode(:kvsfxb, 0x56, {:name => :size, :type => :ushort}, {:name => :from, :type => :ushort}, {:name => :signature, :type => :ushort})
|
76
|
+
# 4 ST -> 1 ST
|
77
|
+
opcode :kvsvb, 0x57
|
78
|
+
|
79
|
+
|
80
|
+
# 0 ST -> 0 ST; IP
|
81
|
+
opcode :jmp, 0x27, {:name => :to, :type => :ushort, :reladdr => 2}
|
82
|
+
# 1 ST -> 0 ST; IP
|
83
|
+
opcode :jz, 0x21, {:name => :to, :type => :ushort, :reladdr => 2}
|
84
|
+
opcode :je, 0x21, {:name => :to, :type => :ushort, :reladdr => 2}
|
85
|
+
# 1 ST -> 0 ST; IP
|
86
|
+
opcode :jnz, 0x26, {:name => :to, :type => :ushort, :reladdr => 2}
|
87
|
+
opcode :jne, 0x26, {:name => :to, :type => :ushort, :reladdr => 2}
|
88
|
+
# 1 ST -> 0 ST; IP
|
89
|
+
opcode :ja, 0x22, {:name => :to, :type => :ushort, :reladdr => 2}
|
90
|
+
opcode :jg, 0x22, {:name => :to, :type => :ushort, :reladdr => 2}
|
91
|
+
# 1 ST -> 0 ST; IP
|
92
|
+
opcode :jae, 0x23, {:name => :to, :type => :ushort, :reladdr => 2}
|
93
|
+
opcode :jge, 0x23, {:name => :to, :type => :ushort, :reladdr => 2}
|
94
|
+
# 1 ST -> 0 ST; IP
|
95
|
+
opcode :jb, 0x24, {:name => :to, :type => :ushort, :reladdr => 2}
|
96
|
+
opcode :jl, 0x24, {:name => :to, :type => :ushort, :reladdr => 2}
|
97
|
+
# 1 ST -> 0 ST; IP
|
98
|
+
opcode :jbe, 0x25, {:name => :to, :type => :ushort, :reladdr => 2}
|
99
|
+
opcode :jle, 0x25, {:name => :to, :type => :ushort, :reladdr => 2}
|
100
|
+
|
101
|
+
# 1 IM_B -> 1 ST
|
102
|
+
opcode :ldbc, 0x30, {:name => :const, :type => :byte}
|
103
|
+
# 1 IM -> 1 ST
|
104
|
+
opcode :ldwc, 0x31, {:name => :const, :type => :short}
|
105
|
+
# 1 ST -> 1 ST
|
106
|
+
opcode :ldb , 0x32, {:name => :from, :type => :ushort}
|
107
|
+
# 1 ST -> 1 ST
|
108
|
+
opcode :ldw , 0x33, {:name => :from, :type => :ushort}
|
109
|
+
# 1 ST -> 1 ST
|
110
|
+
opcode :ldbv, 0x36
|
111
|
+
# 1 ST -> 1 ST
|
112
|
+
opcode :ldwv, 0x37
|
113
|
+
|
114
|
+
# 1 ST -> 0 ST
|
115
|
+
opcode :outnew, 0x42
|
116
|
+
# 1 ST -> 0 ST
|
117
|
+
opcode :outb, 0x44
|
118
|
+
# 1 ST -> 0 ST
|
119
|
+
opcode :outw, 0x45
|
120
|
+
|
121
|
+
# 1 ST -> 0 ST
|
122
|
+
opcode :pop, 0x34
|
123
|
+
# 2 ST -> 0 ST
|
124
|
+
opcode :pop2, 0x35
|
125
|
+
|
126
|
+
# 1 IM, x ST -> 2x ST
|
127
|
+
opcode :dupn, 0x3C, {:name => :n, :type => :ubyte}
|
128
|
+
# 1 IM, x ST -> x ST
|
129
|
+
opcode :flipn, 0x3D, {:name => :n, :type => :ubyte}
|
130
|
+
|
131
|
+
# 2 IM -> 0 ST
|
132
|
+
opcode(:outfxb, 0x40, {:name => :size, :type => :ushort}, {:name => :from, :type => :ushort})
|
133
|
+
# 2 ST -> 0 ST
|
134
|
+
opcode(:outvlb, 0x41, {:name => :from, :type => :ushort})
|
135
|
+
|
136
|
+
|
137
|
+
# 1 IM, 1 ST -> 0 ST
|
138
|
+
opcode :outvb, 0x43
|
139
|
+
# 0 ST -> 0 ST;;
|
140
|
+
opcode :halt, 0x46
|
141
|
+
# 1 ST -> 0 ST
|
142
|
+
opcode :psrm, 0x47
|
143
|
+
|
144
|
+
# 1 ST -> 1 ST
|
145
|
+
opcode :rdk, 0x5A
|
146
|
+
# 1 ST -> 0 ST
|
147
|
+
opcode :relk, 0x5C
|
148
|
+
|
149
|
+
opcode :ldkl, 0x5D
|
150
|
+
# 1 IM_B -> 2 ST
|
151
|
+
opcode :genkp, 0x5E, {:name => :type, :type => :ubyte }
|
152
|
+
# 1 ST, 1 IM -> 1 ST
|
153
|
+
opcode :authk, 0x5F, {:name => :auth, :type => :ushort }
|
154
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Tem::SeClosures
|
4
|
+
module MixedMethods
|
5
|
+
def assemble(&proc_block)
|
6
|
+
return Tem::SecAssembler.new(self).assemble(&proc_block)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
include MixedMethods
|
11
|
+
def self.included(klass)
|
12
|
+
klass.extend MixedMethods
|
13
|
+
end
|
14
|
+
|
15
|
+
def sec_trace
|
16
|
+
#begin
|
17
|
+
response = issue_apdu [0x00, 0x54, 0x00, 0x00, 0x00].flatten
|
18
|
+
trace = reply_data(response)
|
19
|
+
if trace.length > 2
|
20
|
+
case read_tem_short(trace, 0) # trace version
|
21
|
+
when 1
|
22
|
+
return {:sp => read_tem_short(trace, 2), :ip => read_tem_short(trace, 4),
|
23
|
+
:out => read_tem_short(trace, 6), :pscell => read_tem_short(trace, 8)}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
return nil # unreadable trace
|
27
|
+
#rescue
|
28
|
+
# return nil
|
29
|
+
#end
|
30
|
+
end
|
31
|
+
|
32
|
+
def solve_psfault
|
33
|
+
# TODO: better strategy, lol
|
34
|
+
next_cell = rand(16)
|
35
|
+
response = issue_apdu [0x00, 0x53, to_tem_ushort(next_cell), 0x00].flatten
|
36
|
+
tem_error(response) if failure_code(response)
|
37
|
+
end
|
38
|
+
|
39
|
+
def execute(compiled_proc, key_id = 0)
|
40
|
+
# load SECpack
|
41
|
+
buffer_id = post_buffer(compiled_proc.tem_formatted_body)
|
42
|
+
response = issue_apdu [0x00, 0x50, to_tem_byte(buffer_id), to_tem_byte(key_id), 0x00].flatten
|
43
|
+
release_buffer(buffer_id)
|
44
|
+
tem_error(response) if failure_code(response)
|
45
|
+
tem_secpack_error(response) if read_tem_byte(response, 0) != 1
|
46
|
+
|
47
|
+
# execute SEC
|
48
|
+
sec_exception = nil
|
49
|
+
loop do
|
50
|
+
response = issue_apdu [0x00, 0x52, 0x00, 0x00, 0x00].flatten
|
51
|
+
tem_error(response) if failure_code(response)
|
52
|
+
sec_status = read_tem_byte(response, 0)
|
53
|
+
case sec_status
|
54
|
+
when 2 # success
|
55
|
+
break
|
56
|
+
when 3 # exception
|
57
|
+
# there is an exception, try to collect the trace
|
58
|
+
b_stat = stat_buffers() rescue nil
|
59
|
+
k_stat = stat_keys() rescue nil
|
60
|
+
trace = sec_trace()
|
61
|
+
backtrace = (trace && trace[:ip]) ? compiled_proc.stack_for_ip(trace[:ip]) : Kernel.caller
|
62
|
+
sec_exception = Tem::SecExecError.new backtrace, trace, b_stat, k_stat
|
63
|
+
break
|
64
|
+
when 4 # persistent store fault
|
65
|
+
solve_psfault
|
66
|
+
else
|
67
|
+
raise "Unrecognized execution engine status #{sec_status}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# TODO: handle response to figure out if we need to do page faults or something
|
72
|
+
|
73
|
+
# unbind SEC
|
74
|
+
response = issue_apdu [0x00, 0x51, 0x00, 0x00, 0x00].flatten
|
75
|
+
raise sec_exception if sec_exception
|
76
|
+
buffer_id, buffer_length = read_tem_byte(response, 0), read_tem_short(response, 1)
|
77
|
+
data_buffer = read_buffer buffer_id
|
78
|
+
release_buffer buffer_id
|
79
|
+
|
80
|
+
return data_buffer[0...buffer_length]
|
81
|
+
end
|
82
|
+
end
|
data/lib/tem/secpack.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
class Tem::SecPack
|
4
|
+
@@serialized_members = [:body, :labels, :ep, :sp, :extra_bytes, :signed_bytes, :encrypted_bytes, :sealed, :lines]
|
5
|
+
|
6
|
+
def self.new_from_array(array)
|
7
|
+
arg_hash = { :tem_class => Tem::Session }
|
8
|
+
@@serialized_members.each_index { |i| arg_hash[@@serialized_members[i]] = array[i] }
|
9
|
+
self.new(arg_hash)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.new_from_yaml_str(yaml_str)
|
13
|
+
array = YAML.load yaml_str
|
14
|
+
new_from_array array
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_array
|
18
|
+
@@serialized_members.map { |m| self.instance_variable_get('@' + m.to_s) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_yaml_str
|
22
|
+
self.to_array.to_yaml.to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :body, :sealed
|
26
|
+
attr_reader :lines
|
27
|
+
|
28
|
+
def initialize(args)
|
29
|
+
@tem_klass = args[:tem_class]
|
30
|
+
@@serialized_members.map { |m| self.instance_variable_set('@' + m.to_s, args[m]) }
|
31
|
+
@sealed ||= false
|
32
|
+
end
|
33
|
+
|
34
|
+
def label_address(label_name)
|
35
|
+
@labels[label_name.to_sym]
|
36
|
+
end
|
37
|
+
|
38
|
+
def tem_header
|
39
|
+
# TODO: use 0x0100 (no tracing) depending on options
|
40
|
+
hh = [0x0101, @signed_bytes, @encrypted_bytes, @extra_bytes, @sp, @ep].map { |n| @tem_klass.to_tem_ushort n }.flatten
|
41
|
+
hh += Array.new((@tem_klass.hash_for_tem [0]).length - hh.length, 0)
|
42
|
+
return hh
|
43
|
+
end
|
44
|
+
|
45
|
+
def seal(public_key, encrypt_from = 0, plaintext_from = 0)
|
46
|
+
encrypt_from = @labels[encrypt_from.to_sym] unless encrypt_from.instance_of? Numeric
|
47
|
+
plaintext_from = @labels[plaintext_from.to_sym] unless plaintext_from.instance_of? Numeric
|
48
|
+
|
49
|
+
@signed_bytes = encrypt_from
|
50
|
+
@encrypted_bytes = plaintext_from - encrypt_from
|
51
|
+
|
52
|
+
proc_sig = @tem_klass.hash_for_tem [tem_header, @body[0...plaintext_from]].flatten
|
53
|
+
crypt = public_key.encrypt [@body[encrypt_from...plaintext_from], proc_sig].flatten
|
54
|
+
@body = [@body[0...encrypt_from], crypt, @body[plaintext_from..-1]].flatten
|
55
|
+
|
56
|
+
label_delta = crypt.length - @encrypted_bytes
|
57
|
+
@labels = Hash[*(@labels.map { |k, v|
|
58
|
+
if v < encrypt_from
|
59
|
+
[k, v]
|
60
|
+
elsif v < plaintext_from
|
61
|
+
[]
|
62
|
+
else
|
63
|
+
[k, v + label_delta]
|
64
|
+
end
|
65
|
+
}.flatten)]
|
66
|
+
|
67
|
+
@sealed = true
|
68
|
+
end
|
69
|
+
|
70
|
+
def tem_formatted_body()
|
71
|
+
return [tem_header, @body].flatten
|
72
|
+
end
|
73
|
+
|
74
|
+
def stack_for_ip(ip)
|
75
|
+
return nil unless @lines
|
76
|
+
|
77
|
+
max_value = -1
|
78
|
+
st = nil
|
79
|
+
@lines.each do |st_ip, stack|
|
80
|
+
# if something breaks, it's likely to happen after the opcode
|
81
|
+
# of the offending instruction has been read, so assume offending_ip < ip
|
82
|
+
max_value, st = st_ip, stack if st_ip < ip && max_value < st_ip
|
83
|
+
end
|
84
|
+
return st
|
85
|
+
end
|
86
|
+
end
|
data/lib/tem/tag.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Tem::Tag
|
2
|
+
def set_tag(tag_data)
|
3
|
+
buffer_id = post_buffer(tag_data)
|
4
|
+
response = issue_apdu [0x00, 0x30, to_tem_byte(buffer_id), 0x00, 0x00].flatten
|
5
|
+
tem_error(response) if failure_code(response)
|
6
|
+
release_buffer(buffer_id)
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_tag_length
|
10
|
+
response = issue_apdu [0x00, 0x31, 0x00, 0x00, 0x00].flatten
|
11
|
+
tem_error(response) if failure_code(response)
|
12
|
+
return read_tem_short(response, 0)
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_tag_data(offset, length)
|
16
|
+
buffer_id = alloc_buffer(length)
|
17
|
+
response = issue_apdu [0x00, 0x32, to_tem_byte(buffer_id), 0x00, 0x04, to_tem_short(offset), to_tem_short(length)].flatten
|
18
|
+
tem_error(response) if failure_code(response)
|
19
|
+
tag_data = read_buffer(buffer_id)
|
20
|
+
release_buffer(buffer_id)
|
21
|
+
return tag_data
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_tag
|
25
|
+
tag_length = self.get_tag_length
|
26
|
+
get_tag_data(0, tag_length)
|
27
|
+
end
|
28
|
+
end
|
data/lib/tem/tem.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
class Tem::Session
|
4
|
+
include Tem::Abi
|
5
|
+
include Tem::Buffers
|
6
|
+
include Tem::CA
|
7
|
+
include Tem::CryptoAbi
|
8
|
+
include Tem::ECert
|
9
|
+
include Tem::Keys
|
10
|
+
include Tem::Lifecycle
|
11
|
+
include Tem::SeClosures
|
12
|
+
include Tem::Tag
|
13
|
+
include Tem::Toolkit
|
14
|
+
|
15
|
+
@@aid = [0x19, 0x83, 0x12, 0x29, 0x10, 0xBA, 0xBE]
|
16
|
+
|
17
|
+
def initialize(javacard)
|
18
|
+
@card = javacard
|
19
|
+
@card.select_applet(@@aid)
|
20
|
+
end
|
21
|
+
|
22
|
+
def disconnect
|
23
|
+
# TODO: deselect applet, reset card
|
24
|
+
@card = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def issue_apdu(apdu)
|
28
|
+
@card.issue_apdu apdu
|
29
|
+
end
|
30
|
+
|
31
|
+
def failure_code(reply_apdu)
|
32
|
+
@card.failure_code reply_apdu
|
33
|
+
end
|
34
|
+
|
35
|
+
def reply_data(reply_apdu)
|
36
|
+
@card.reply_data reply_apdu
|
37
|
+
end
|
38
|
+
|
39
|
+
def tem_error(response)
|
40
|
+
fcode = failure_code response
|
41
|
+
raise "TEM returned error 0x#{'%04x' % fcode} while processing the request"
|
42
|
+
end
|
43
|
+
|
44
|
+
def tem_secpack_error(response)
|
45
|
+
raise "TEM refused the SECpack"
|
46
|
+
end
|
47
|
+
end
|
data/lib/tem/toolkit.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
module Tem::Toolkit
|
2
|
+
def tk_firmware_ver
|
3
|
+
tag = get_tag
|
4
|
+
return { :major => read_tem_ubyte(tag, 0), :minor => read_tem_ubyte(tag, 1) }
|
5
|
+
end
|
6
|
+
|
7
|
+
def tk_gen_key(type = :asymmetric, authz = nil)
|
8
|
+
gen_sec = assemble do |s|
|
9
|
+
s.ldbc authz.nil? ? 24 : 4
|
10
|
+
s.outnew
|
11
|
+
if authz.nil?
|
12
|
+
# no authorization given, must generate one
|
13
|
+
s.ldbc 20
|
14
|
+
s.ldwc :key_auth
|
15
|
+
s.dupn :n => 2
|
16
|
+
s.rnd
|
17
|
+
s.outvb
|
18
|
+
end
|
19
|
+
s.genkp :type => (type == :asymmetric) ? 0x00 : 0x80
|
20
|
+
s.authk :auth => :key_auth
|
21
|
+
s.outw
|
22
|
+
s.authk :auth => :key_auth
|
23
|
+
s.outw
|
24
|
+
s.halt
|
25
|
+
s.label :key_auth
|
26
|
+
if authz.nil?
|
27
|
+
s.filler :ubyte, 20
|
28
|
+
else
|
29
|
+
s.immed :ubyte, authz
|
30
|
+
end
|
31
|
+
s.stack
|
32
|
+
s.extra 8
|
33
|
+
end
|
34
|
+
|
35
|
+
kp_buffer = execute gen_sec
|
36
|
+
keys_offset = authz.nil? ? 20 : 0
|
37
|
+
k1id, k2id = read_tem_ushort(kp_buffer, keys_offset), read_tem_ushort(kp_buffer, keys_offset + 2)
|
38
|
+
if type == :asymmetric
|
39
|
+
return_val = { :pubk_id => k1id, :privk_id => k2id }
|
40
|
+
else
|
41
|
+
return_val = { :key_id => k1id }
|
42
|
+
end
|
43
|
+
return { :authz => authz.nil? ? kp_buffer[0...20] : authz }.merge!(return_val)
|
44
|
+
end
|
45
|
+
|
46
|
+
def tk_read_key(key_id, authz)
|
47
|
+
read_sec = assemble do |s|
|
48
|
+
s.ldbc :const => key_id
|
49
|
+
s.authk :auth => :key_auth
|
50
|
+
s.ldkl
|
51
|
+
s.outnew
|
52
|
+
s.ldbc :const => key_id
|
53
|
+
s.ldbc(-1)
|
54
|
+
s.stk
|
55
|
+
s.halt
|
56
|
+
s.label :key_auth
|
57
|
+
s.immed :ubyte, authz
|
58
|
+
s.stack
|
59
|
+
s.extra 8
|
60
|
+
end
|
61
|
+
|
62
|
+
key_string = execute read_sec
|
63
|
+
return read_tem_key(key_string, 0)
|
64
|
+
end
|
65
|
+
|
66
|
+
def tk_delete_key(key_id, authz)
|
67
|
+
del_sec = assemble do |s|
|
68
|
+
s.ldbc :const => key_id
|
69
|
+
s.authk :auth => :key_auth
|
70
|
+
s.relk
|
71
|
+
s.ldbc :const => 1
|
72
|
+
s.outnew
|
73
|
+
s.ldbc :const => key_id
|
74
|
+
s.outb
|
75
|
+
s.halt
|
76
|
+
s.label :key_auth
|
77
|
+
s.immed :ubyte, authz
|
78
|
+
s.stack
|
79
|
+
s.extra 8
|
80
|
+
end
|
81
|
+
|
82
|
+
execute del_sec
|
83
|
+
end
|
84
|
+
|
85
|
+
def tk_post_key(key, authz)
|
86
|
+
post_sec = assemble do |s|
|
87
|
+
s.ldbc :const => 1
|
88
|
+
s.outnew
|
89
|
+
s.ldwc :const => :key_data
|
90
|
+
s.rdk
|
91
|
+
s.authk :auth => :key_auth
|
92
|
+
s.outb
|
93
|
+
s.halt
|
94
|
+
s.label :key_data
|
95
|
+
s.immed :ubyte, key.to_tem_key
|
96
|
+
s.label :key_auth
|
97
|
+
s.immed :ubyte, authz
|
98
|
+
s.stack
|
99
|
+
s.extra 8
|
100
|
+
end
|
101
|
+
id_string = execute post_sec
|
102
|
+
return read_tem_ubyte(id_string, 0)
|
103
|
+
end
|
104
|
+
end
|
data/lib/tem_ruby.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# gems
|
2
|
+
require 'smartcard'
|
3
|
+
|
4
|
+
module Tem
|
5
|
+
end
|
6
|
+
|
7
|
+
module Tem::SCard
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'scard/pcsc_terminal.rb'
|
11
|
+
require 'scard/jcop_remote_terminal.rb'
|
12
|
+
require 'scard/java_card.rb'
|
13
|
+
|
14
|
+
require 'tem/abi.rb'
|
15
|
+
require 'tem/buffers.rb'
|
16
|
+
require 'tem/ca.rb'
|
17
|
+
require 'tem/crypto_abi.rb'
|
18
|
+
require 'tem/ecert.rb'
|
19
|
+
require 'tem/hive.rb'
|
20
|
+
require 'tem/keys.rb'
|
21
|
+
require 'tem/lifecycle.rb'
|
22
|
+
require 'tem/sec_assembler.rb'
|
23
|
+
require 'tem/sec_opcodes.rb'
|
24
|
+
require 'tem/sec_exec_error.rb'
|
25
|
+
require 'tem/seclosures.rb'
|
26
|
+
require 'tem/secpack.rb'
|
27
|
+
require 'tem/tag.rb'
|
28
|
+
require 'tem/toolkit.rb'
|
29
|
+
require 'tem/tem.rb'
|
data/tem_ruby.gemspec
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
# Gem::Specification for Tem_ruby-0.9.0
|
3
|
+
# Originally generated by Echoe
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = %q{tem_ruby}
|
7
|
+
s.version = "0.9.0"
|
8
|
+
|
9
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.authors = ["Victor Costan"]
|
13
|
+
s.date = %q{2008-06-11}
|
14
|
+
s.description = %q{TEM (Trusted Execution Module) driver, written in and for ruby.}
|
15
|
+
s.email = %q{victor@costan.us}
|
16
|
+
s.executables = ["tem_stat", "tem_ca", "tem_irb", "tem_bench"]
|
17
|
+
s.extra_rdoc_files = ["bin/tem_stat", "bin/tem_ca", "bin/tem_irb", "bin/tem_bench", "LICENSE", "lib/scard/java_card.rb", "lib/scard/jcop_remote_terminal.rb", "lib/scard/pcsc_terminal.rb", "lib/tem_ruby.rb", "lib/tem/tag.rb", "lib/tem/keys.rb", "lib/tem/sec_opcodes.rb", "lib/tem/_cert.rb", "lib/tem/buffers.rb", "lib/tem/toolkit.rb", "lib/tem/tem.rb", "lib/tem/abi.rb", "lib/tem/crypto_abi.rb", "lib/tem/ca.rb", "lib/tem/secpack.rb", "lib/tem/sec_exec_error.rb", "lib/tem/sec_assembler.rb", "lib/tem/lifecycle.rb", "lib/tem/ecert.rb", "lib/tem/hive.rb", "lib/tem/seclosures.rb", "README", "CHANGELOG"]
|
18
|
+
s.has_rdoc = true
|
19
|
+
s.homepage = %q{http://tem.rubyforge.org}
|
20
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Tem_ruby", "--main", "README"]
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
s.rubyforge_project = %q{tem}
|
23
|
+
s.rubygems_version = %q{1.1.1}
|
24
|
+
s.summary = %q{TEM (Trusted Execution Module) driver, written in and for ruby.}
|
25
|
+
s.test_files = ["test/test_driver.rb", "test/test_tem.rb", "test/test_exceptions.rb"]
|
26
|
+
|
27
|
+
s.add_dependency(%q<smartcard>, [">= 0.2.2"])
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# # Original Rakefile source (requires the Echoe gem):
|
32
|
+
#
|
33
|
+
# require 'rubygems'
|
34
|
+
# gem 'echoe'
|
35
|
+
# require 'echoe'
|
36
|
+
#
|
37
|
+
# Echoe.new('tem_ruby') do |p|
|
38
|
+
# p.project = 'tem' # rubyforge project
|
39
|
+
#
|
40
|
+
# p.author = 'Victor Costan'
|
41
|
+
# p.email = 'victor@costan.us'
|
42
|
+
# p.summary = 'TEM (Trusted Execution Module) driver, written in and for ruby.'
|
43
|
+
# p.url = 'http://tem.rubyforge.org'
|
44
|
+
# p.dependencies = ['smartcard >=0.2.2']
|
45
|
+
#
|
46
|
+
# p.need_tar_gz = false
|
47
|
+
# p.rdoc_pattern = /^(lib|bin|tasks|ext)|^BUILD|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# if $0 == __FILE__
|
51
|
+
# Rake.application = Rake::Application.new
|
52
|
+
# Rake.application.run
|
53
|
+
# end
|