tem_ruby 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|