tem_ruby 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,98 @@
1
+ module Tem::Buffers
2
+ def alloc_buffer(length)
3
+ apdu = [0x00, 0x20, to_tem_short(length), 0x00].flatten
4
+ response = issue_apdu apdu
5
+ tem_error(response) if failure_code(response)
6
+ return read_tem_byte(response, 0)
7
+ end
8
+
9
+ def release_buffer(buffer_id)
10
+ apdu = [0x00, 0x21, to_tem_byte(buffer_id), 0x00, 0x00].flatten
11
+ response = issue_apdu apdu
12
+ tem_error(response) if failure_code(response)
13
+ return true
14
+ end
15
+
16
+ def flush_buffers
17
+ apdu = [0x00, 0x26, 0x00, 0x00, 0x00].flatten
18
+ response = issue_apdu apdu
19
+ tem_error(response) if failure_code(response)
20
+ return true
21
+ end
22
+
23
+ def get_buffer_length(buffer_id)
24
+ apdu = [0x00, 0x22, to_tem_byte(buffer_id), 0x00, 0x00].flatten
25
+ response = issue_apdu apdu
26
+ tem_error(response) if failure_code(response)
27
+ return read_tem_short(response, 0)
28
+ end
29
+
30
+ def read_buffer(buffer_id)
31
+ @buffer_chunk_size = guess_buffer_chunk_size unless defined? @buffer_chunk_size
32
+
33
+ buffer = []
34
+ chunk_id = 0
35
+ while true do
36
+ apdu = [0x00, 0x23, to_tem_byte(buffer_id), to_tem_byte(chunk_id), 0x00].flatten
37
+ response = issue_apdu apdu
38
+ tem_error(response) if failure_code(response)
39
+ buffer += response[0...(response.length - 2)]
40
+ break if response.length != @buffer_chunk_size + 2
41
+ chunk_id += 1
42
+ end
43
+ return buffer
44
+ end
45
+
46
+ def write_buffer(buffer_id, data)
47
+ @buffer_chunk_size = guess_buffer_chunk_size unless defined? @buffer_chunk_size
48
+
49
+ chunk_id, offset = 0, 0
50
+ while offset < data.length do
51
+ write_size = (data.length - offset < @buffer_chunk_size) ?
52
+ data.length - offset : @buffer_chunk_size
53
+ apdu = [0x00, 0x24, to_tem_byte(buffer_id), to_tem_byte(chunk_id), to_tem_ubyte(write_size),
54
+ data.values_at(offset...(offset+write_size))].flatten
55
+ response = issue_apdu apdu
56
+ tem_error(response) if failure_code(response)
57
+
58
+ chunk_id += 1
59
+ offset += write_size
60
+ end
61
+ end
62
+
63
+ def guess_buffer_chunk_size
64
+ apdu = [0x00, 0x25, 0x00, 0x00, 0x00].flatten
65
+ response = issue_apdu apdu
66
+ tem_error(response) if failure_code(response)
67
+ return read_tem_short(response, 0)
68
+ end
69
+
70
+ def stat_buffers
71
+ apdu = [0x00, 0x27, 0x00, 0x00, 0x00].flatten
72
+ response = issue_apdu apdu
73
+ tem_error(response) if failure_code(response)
74
+ response = reply_data(response)
75
+ memory_types = [:persistent, :clear_on_reset, :clear_on_deselect]
76
+ stat = {:free => {}, :buffers => []}
77
+ memory_types.each_with_index { |mt, i| stat[:free][mt] = read_tem_short(response, i * 2) }
78
+ offset = 6
79
+ i = 0
80
+ while offset < response.length do
81
+ stat[:buffers][i] =
82
+ {:type => memory_types[read_tem_ubyte(response, offset) & 0x3f],
83
+ :pinned => (read_tem_ubyte(response, offset) & 0x80) != 0,
84
+ :free => (read_tem_ubyte(response, offset) & 0x40) == 0,
85
+ :length => read_tem_ushort(response, offset + 1),
86
+ :xlength => read_tem_ushort(response, offset + 3)}
87
+ offset += 5
88
+ i += 1
89
+ end
90
+ return stat
91
+ end
92
+
93
+ def post_buffer(data)
94
+ buffer_id = alloc_buffer(data.length)
95
+ write_buffer buffer_id, data
96
+ return buffer_id
97
+ end
98
+ end
data/lib/tem/ca.rb ADDED
@@ -0,0 +1,114 @@
1
+ require 'openssl'
2
+ require 'yaml'
3
+
4
+ # Certificate Authority (CA) functionality for TEM manufacturers
5
+ module Tem::CA
6
+ # creates an Endorsement Certificate for a TEM's Public Endorsement Key
7
+ def new_ecert(pubek)
8
+ ca_cert = Tem::CA.ca_cert
9
+ ca_key = Tem::CA.ca_key
10
+ conf = Tem::CA.config
11
+
12
+ dn = OpenSSL::X509::Name.new conf[:issuer].merge(conf[:subject]).to_a
13
+ now = Time.now
14
+ ecert = OpenSSL::X509::Certificate.new
15
+ ecert.issuer = ca_cert.subject
16
+ ecert.subject = dn
17
+ ecert.not_before = now;
18
+ ecert.not_after = now + conf[:ecert_validity_days] * 60 * 60 * 24;
19
+ ecert.public_key = pubek
20
+ ecert.version = 2
21
+ cf = OpenSSL::X509::ExtensionFactory.new
22
+ cf.subject_certificate = ecert
23
+ cf.issuer_certificate = ca_cert
24
+ ecert.add_extension cf.create_extension("basicConstraints", "CA:true", true)
25
+ ecert.add_extension cf.create_extension("authorityKeyIdentifier", "keyid,issuer")
26
+ ecert.add_extension cf.create_extension("keyUsage", "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign")
27
+ ecert.add_extension cf.create_extension("extendedKeyUsage", "serverAuth,clientAuth,codeSigning,emailProtection,timeStamping,msCodeInd,msCodeCom,msCTLSign,msSGC,msEFS,nsSGC")
28
+ ecert.add_extension cf.create_extension("nsCertType", "client,server,email,objsign,sslCA,emailCA,objCA")
29
+ ecert.add_extension cf.create_extension("subjectKeyIdentifier", "hash")
30
+ ecert.sign ca_key, OpenSSL::Digest::SHA1.new
31
+
32
+ return ecert
33
+ end
34
+
35
+ @@dev_dir = File.join(File.dirname(__FILE__), "..", "..", "dev_ca")
36
+
37
+ # retrieves the TEM CA configuration
38
+ def self.config
39
+ cpath = Tem::Hive.path_to 'ca/config.yml'
40
+ cpath = File.join(@@dev_dir, 'config.yml') unless File.exists? cpath
41
+
42
+ # try to open it in the base folder
43
+ scaffold_config unless File.exists? cpath
44
+ return File.open(cpath, 'r') { |f| YAML.load f }
45
+ end
46
+
47
+ # retrieves the TEM CA certificate
48
+ def self.ca_cert
49
+ cpath = Tem::Hive.path_to 'ca/ca_cert.pem'
50
+ cpath = File.join(@@dev_dir, 'ca_cert.pem') unless File.exists? cpath
51
+ return OpenSSL::X509::Certificate.new(File.open(cpath, 'r') { |f| f.read })
52
+ end
53
+
54
+ # retrieves the TEM CA key pair (needed for signing)
55
+ def self.ca_key
56
+ cpath = Tem::Hive.path_to 'ca/ca_key.pem'
57
+ cpath = File.join(@@dev_dir, 'ca_key.pem') unless File.exists? cpath
58
+ return OpenSSL::PKey::RSA.new(File.open(cpath, 'r') { |f| f.read })
59
+ end
60
+
61
+ # scaffolds the structures needed for a TEM CA
62
+ def self.scaffold_ca
63
+ conf = config
64
+
65
+ # generate and write key
66
+ ca_key = Tem::CryptoAbi.generate_ssl_kp
67
+ key_path = Tem::Hive.create 'ca/ca_key.pem'
68
+ File.open(key_path, 'w') { |f| f.write ca_key.to_pem }
69
+
70
+ # create the CA certificate
71
+ dn = OpenSSL::X509::Name.new conf[:issuer].to_a
72
+ now = Time.now
73
+ cert = OpenSSL::X509::Certificate.new
74
+ cert.subject = cert.issuer = dn
75
+ cert.not_before = now;
76
+ cert.not_after = now + conf[:ca_validity_days] * 60 * 60 * 24;
77
+ cert.public_key = ca_key.public_key
78
+ cert.version = 2
79
+ cf = OpenSSL::X509::ExtensionFactory.new
80
+ cf.subject_certificate = cf.issuer_certificate = cert
81
+ cert.add_extension cf.create_extension("basicConstraints", "CA:true", true)
82
+ cert.add_extension cf.create_extension("authorityKeyIdentifier", "keyid,issuer")
83
+ cert.add_extension cf.create_extension("keyUsage", "cRLSign,keyCertSign")
84
+ cert.add_extension cf.create_extension("nsCertType", "emailCA,sslCA")
85
+ cert.add_extension cf.create_extension("subjectKeyIdentifier", "hash")
86
+ cert.sign ca_key, OpenSSL::Digest::SHA1.new
87
+
88
+ # write the CA certificate
89
+ cert_path = Tem::Hive.create 'ca/ca_cert.pem'
90
+ File.open(cert_path, 'w') { |f| f.write cert.to_pem }
91
+ cert_path = Tem::Hive.create 'ca/ca_cert.cer'
92
+ File.open(cert_path, 'wb') { |f| f.write cert.to_der }
93
+ end
94
+
95
+ # scaffolds a TEM CA configuration
96
+ def self.scaffold_config
97
+ def_config = {
98
+ :issuer => {
99
+ 'C' => 'US', 'ST' => 'Massachusetts', 'L' => 'Cambridge',
100
+ 'O' => 'Massachusetts Insitute of Technology',
101
+ 'OU' => 'Computer Science and Artificial Intelligence Laboratory',
102
+ 'CN' => 'Trusted Execution Module Development CA'
103
+ },
104
+ :subject => {
105
+ 'CN' => 'Trusted Execution Module DevChip'
106
+ },
107
+ :ca_validity_days => 3652,
108
+ :ecert_validity_days => 365 * 2,
109
+ }
110
+
111
+ cpath = Tem::Hive.create 'ca/config.yml'
112
+ File.open(cpath, 'w') { |f| YAML.dump def_config, f }
113
+ end
114
+ end
@@ -0,0 +1,216 @@
1
+ require 'openssl'
2
+ require 'digest'
3
+ require 'yaml'
4
+
5
+ module Tem::CryptoAbi
6
+ include Tem::Abi
7
+
8
+ # contains the methods
9
+ module MixedMethods
10
+ def read_tem_bignum(buffer, offset, length)
11
+ return buffer[offset...(offset+length)].inject(0) { |num, digit| num = (num << 8) | digit }
12
+ end
13
+
14
+ def to_tem_bignum(n)
15
+ if n.kind_of? OpenSSL::BN
16
+ len = n.num_bytes
17
+ bytes = (0...len).map do |i|
18
+ bit_i = (len - i) * 8
19
+ v = 0
20
+ 1.upto(8) do
21
+ bit_i -= 1
22
+ v = (v << 1) | (n.bit_set?(bit_i) ? 1 : 0)
23
+ end
24
+ v
25
+ end
26
+ return bytes
27
+ else
28
+ q = 0
29
+ until n == 0 do
30
+ q << (n & 0xFF)
31
+ n >>= 8
32
+ end
33
+ return q.reverse
34
+ end
35
+ end
36
+
37
+ def load_tem_key_material(key, syms, buffer, offset)
38
+ lengths = (0...syms.length).map { |i| read_tem_short(buffer, offset + i * 2)}
39
+ offsets = [offset + syms.length * 2]
40
+ 1.upto(syms.length - 1) { |i| offsets[i] = offsets[i - 1] + lengths[i - 1] }
41
+ 0.upto(syms.length - 1) do |i|
42
+ key.send((syms[i].to_s + '=').to_sym, read_tem_bignum(buffer, offsets[i], lengths[i]))
43
+ end
44
+ end
45
+
46
+ def read_tem_key(buffer, offset)
47
+ key_type = read_tem_ubyte buffer, offset
48
+ if key_type == 0xAA || key_type == 0x55
49
+ key = OpenSSL::PKey::RSA.new
50
+ syms = (key_type == 0xAA) ? [:e, :n] : [:p, :q, :dmp1, :dmq1, :iqmp]
51
+ load_tem_key_material key, syms, buffer, offset + 1
52
+ if key_type == 0x55
53
+ # a bit of math to rebuild the public key
54
+ key.n = key.p * key.q
55
+ p1, q1 = key.p - 1, key.q - 1
56
+ p1q1 = p1 * q1
57
+ # HACK: I haven't figured out how to restore d from dmp1 and dmq1, so
58
+ # I'm betting on the fact that e must be a small prime
59
+ emp1 = key.dmp1.mod_inverse(p1)
60
+ emq1 = key.dmq1.mod_inverse(q1)
61
+ key.e = (emp1 < emq1) ? emp1 : emq1
62
+ key.d = key.e.mod_inverse(p1q1)
63
+ end
64
+ return new_key_from_ssl(key, (key_type == 0xAA))
65
+ else
66
+ raise "Invalid key type #{'%02x' % key_type}"
67
+ end
68
+ end
69
+
70
+ def to_tem_key(ssl_key, type)
71
+ if [:private, :public].include? type
72
+ # asymmetric key
73
+ syms = (type == :public) ? [:e, :n] : [:p, :q, :dmp1, :dmq1, :iqmp]
74
+ numbers = syms.map { |s| to_tem_bignum ssl_key.send(s) }
75
+ return [(type == :public) ? 0xAA : 0x55, numbers.map { |n| to_tem_ushort(n.length) }, numbers].flatten
76
+ else
77
+ # symmetric key
78
+ end
79
+ end
80
+
81
+ def new_key_from_ssl(ssl_key, is_public)
82
+ AsymmetricKey.new(ssl_key, is_public, :pkcs1)
83
+ end
84
+
85
+ def hash_for_tem(data)
86
+ if data.kind_of? String
87
+ data_string = data
88
+ else
89
+ data_string = data.pack('C*')
90
+ end
91
+ digest_string = Digest::SHA1.digest(data_string)
92
+ return digest_string.unpack('C*')
93
+ end
94
+ end
95
+
96
+ self.extend MixedMethods
97
+ include MixedMethods
98
+ def self.included(klass)
99
+ klass.extend MixedMethods
100
+ end
101
+
102
+ def hash_for_tem(data)
103
+ Tem::CryptoAbi.hash_for_tem data
104
+ end
105
+
106
+ def self.load_ssl(ssl_key)
107
+ return {:pubkey => AsymmetricKey.new(ssl_key, true, :pkcs1), :privkey => AsymmetricKey.new(ssl_key, false, :pkcs1) }
108
+ end
109
+
110
+ def self.generate_ssl_kp
111
+ return Tem::CryptoAbi::AsymmetricKey.generate_ssl_kp
112
+ end
113
+
114
+ class AsymmetricKey
115
+ attr_reader :ssl_key
116
+
117
+ def self.new_from_array(array)
118
+ AsymmetricKey.new(OpenSSL::PKey::RSA.new(array[0]), *array[1..-1])
119
+ end
120
+
121
+ def self.new_from_yaml_str(yaml_str)
122
+ array = YAML.load yaml_str
123
+ new_from_array array
124
+ end
125
+
126
+ def to_array
127
+ [@ssl_key.to_pem, @is_public, @padding_type]
128
+ end
129
+
130
+ def to_yaml_str
131
+ self.to_array.to_yaml.to_s
132
+ end
133
+
134
+ def self.generate_ssl_kp
135
+ return OpenSSL::PKey::RSA.generate(2048, 65537)
136
+ end
137
+ def initialize(ssl_key, is_public, padding_type)
138
+ @ssl_key = ssl_key
139
+ @is_public = is_public ? true : false
140
+ @padding_type = padding_type
141
+
142
+ case padding_type
143
+ when :oaep
144
+ @padding_id = OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
145
+ @padding_bytes = 42
146
+ when :pkcs1
147
+ @padding_id = OpenSSL::PKey::RSA::PKCS1_PADDING
148
+ @padding_bytes = 11
149
+ else
150
+ raise "Unknown padding type #{padding_type}\n"
151
+ end
152
+
153
+ @size = 0
154
+ n = is_public ? @ssl_key.n : (@ssl_key.p * @ssl_key.q)
155
+ while n != 0 do
156
+ @size += 1
157
+ n >>= 8
158
+ end
159
+ end
160
+
161
+ def to_tem_key
162
+ Tem::CryptoAbi.to_tem_key @ssl_key, (@is_public ? :public : :private)
163
+ end
164
+
165
+ def chug_data(data, in_size, &chug_block)
166
+ output = data.class.new
167
+ i = 0
168
+ while i < data.length do
169
+ block_size = (data.length - i < in_size) ? data.length - i : in_size
170
+ if data.kind_of? String
171
+ block = data[i...(i+block_size)]
172
+ else
173
+ block = data[i...(i+block_size)].pack('C*')
174
+ end
175
+ o_block = yield block
176
+ if data.kind_of? String
177
+ output += o_block
178
+ else
179
+ output += o_block.unpack('C*')
180
+ end
181
+ i += block_size
182
+ end
183
+ return output
184
+ end
185
+
186
+ def encrypt_decrypt(data, in_size, op)
187
+ chug_data(data, in_size) { |block| @ssl_key.send op, block, @padding_id }
188
+ end
189
+
190
+ def encrypt(data)
191
+ encrypt_decrypt(data, @size - @padding_bytes, @is_public ? :public_encrypt : :private_encrypt)
192
+ end
193
+
194
+ def decrypt(data)
195
+ encrypt_decrypt(data, @size, @is_public ? :public_decrypt : :private_decrypt)
196
+ end
197
+
198
+ def sign(data)
199
+ in_data = if data.kind_of? String then data else data.pack('C*') end
200
+ # PKCS1-padding is forced in by openssl... sigh!
201
+ out_data = @ssl_key.sign OpenSSL::Digest::SHA1.new, in_data
202
+ if data.kind_of? String then out_data else out_data.unpack('C*') end
203
+ end
204
+
205
+ def verify(data, signature)
206
+ in_data = if data.kind_of? String then data else data.pack('C*') end
207
+ in_signature = if signature.kind_of? String then signature else signature.pack('C*') end
208
+ # PKCS1-padding is forced in by openssl... sigh!
209
+ @ssl_key.verify OpenSSL::Digest::SHA1.new, in_signature, in_data
210
+ end
211
+
212
+ def is_public?
213
+ @is_public
214
+ end
215
+ end
216
+ end
data/lib/tem/ecert.rb ADDED
@@ -0,0 +1,78 @@
1
+ require 'openssl'
2
+
3
+ module Tem::ECert
4
+ # writes an Endorsement Certificate to the TEM's tag
5
+ def set_ecert(ecert)
6
+ set_tag ecert.to_der.unpack('C*')
7
+ end
8
+
9
+ # retrieves the TEM's Endorsement Certificate
10
+ def endorsement_cert
11
+ OpenSSL::X509::Certificate.new get_tag[2..-1].pack('C*')
12
+ end
13
+
14
+ # retrieves the certificate of the TEM's Manfacturer (CA)
15
+ def manufacturer_cert
16
+ Tem::CA.ca_cert
17
+ end
18
+
19
+ # retrieves the TEM's Public Endorsement Key
20
+ def pubek
21
+ new_key_from_ssl endorsement_cert.public_key, true
22
+ end
23
+
24
+ # emits a TEM
25
+ def emit
26
+ emit_proc = assemble do |p|
27
+ # generate EK, compare with (0, 1)
28
+ p.genkp :type => 0
29
+ p.ldbc 1
30
+ p.sub
31
+ p.jne :to => :not_ok
32
+ p.ldbc 0
33
+ p.sub
34
+ p.jne :to => :not_ok
35
+
36
+ # generate and output random authorization for PrivEK
37
+ p.ldbc 20
38
+ p.dupn :n => 1
39
+ p.outnew
40
+ p.ldwc :privek_auth
41
+ p.dupn :n => 2
42
+ p.rnd
43
+ p.outvb
44
+ # set authorizations for PrivEK and PubkEK
45
+ p.ldbc 0
46
+ p.authk :auth => :privek_auth
47
+ p.ldbc 1 # PubEK always has its initial authorization be all zeroes
48
+ p.authk :auth => :pubek_auth
49
+ p.halt
50
+
51
+ # emitting didn't go well, return nothing and leave
52
+ p.label :not_ok
53
+ p.ldbc 0
54
+ p.outnew
55
+ p.halt
56
+
57
+ p.label :privek_auth
58
+ p.filler :ubyte, 20
59
+ p.label :pubek_auth
60
+ p.filler :ubyte, 20
61
+ p.stack
62
+ p.extra 8
63
+ end
64
+
65
+ r = execute emit_proc
66
+ if r.length == 0
67
+ return nil
68
+ else
69
+ privk_auth = r[0...20]
70
+ pubek_auth = (0...20).map {|i| 0}
71
+ pubek = tk_read_key 1, pubek_auth
72
+ tk_delete_key 1, pubek_auth
73
+ ecert = new_ecert pubek.ssl_key
74
+ set_ecert ecert
75
+ return { :privek_auth => privk_auth }
76
+ end
77
+ end
78
+ end
data/lib/tem/hive.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'fileutils'
3
+
4
+ # The TEM's configuation hive
5
+ module Tem::Hive
6
+ @@hive_dir = File.join(Gem.user_home, ".tem")
7
+
8
+ def self.path_to(*hive_entry)
9
+ File.join(@@hive_dir, *hive_entry)
10
+ end
11
+
12
+ def self.create(*hive_entry)
13
+ path = File.join(@@hive_dir, *hive_entry)
14
+ FileUtils.mkdir_p File.dirname(path)
15
+ File.open(path, "w") { |f| }
16
+ return path
17
+ end
18
+ end
data/lib/tem/keys.rb ADDED
@@ -0,0 +1,60 @@
1
+ module Tem::Keys
2
+ def devchip_generate_key_pair
3
+ response = issue_apdu [0x00, 0x40, 0x00, 0x00, 0x00].flatten
4
+ tem_error(response) if failure_code(response)
5
+ return { :privkey_id => read_tem_byte(response, 0), :pubkey_id => read_tem_byte(response, 1) }
6
+ end
7
+
8
+ def devchip_release_key(key_id)
9
+ response = issue_apdu [0x00, 0x41, to_tem_byte(key_id), 0x00, 0x00].flatten
10
+ tem_error(response) if failure_code(response)
11
+ return true
12
+ end
13
+
14
+ def devchip_save_key(key_id)
15
+ response = issue_apdu [0x00, 0x43, to_tem_byte(key_id), 0x00, 0x00].flatten
16
+ tem_error(response) if failure_code(response)
17
+
18
+ buffer_id, buffer_length = read_tem_byte(response, 0), read_tem_short(response, 1)
19
+ key_buffer = read_buffer buffer_id
20
+ release_buffer buffer_id
21
+
22
+ read_tem_key key_buffer[0...buffer_length], 0
23
+ end
24
+
25
+ def devchip_encrypt_decrypt(data, key_id, opcode)
26
+ buffer_id = post_buffer data
27
+ response = issue_apdu [0x00, opcode, to_tem_byte(key_id), to_tem_byte(buffer_id), 0x00].flatten
28
+ release_buffer buffer_id
29
+ tem_error(response) if failure_code(response)
30
+
31
+ buffer_id, buffer_length = read_tem_byte(response, 0), read_tem_short(response, 1)
32
+ data_buffer = read_buffer buffer_id
33
+ release_buffer buffer_id
34
+
35
+ return data_buffer[0...buffer_length]
36
+ end
37
+ def devchip_encrypt(data, key_id)
38
+ devchip_encrypt_decrypt(data, key_id, 0x44)
39
+ end
40
+ def devchip_decrypt(data, key_id)
41
+ devchip_encrypt_decrypt(data, key_id, 0x45)
42
+ end
43
+
44
+ def stat_keys
45
+ apdu = [0x00, 0x27, 0x01, 0x00, 0x00].flatten
46
+ response = issue_apdu apdu
47
+ tem_error(response) if failure_code(response)
48
+ response = reply_data(response)
49
+ key_types = {0x99 => :symmetric, 0x55 => :private, 0xAA => :public}
50
+ stat = {:keys => {}}
51
+ offset = 0
52
+ while offset < response.length do
53
+ stat[:keys][read_tem_ubyte(response, offset)] =
54
+ {:type => key_types[read_tem_ubyte(response, offset + 1)],
55
+ :bits => read_tem_ushort(response, offset + 2)}
56
+ offset += 4
57
+ end
58
+ return stat
59
+ end
60
+ end
@@ -0,0 +1,8 @@
1
+ module Tem::Lifecycle
2
+ def activate
3
+ issue_apdu([0x00, 0x10, 0x00, 0x00, 0x00])[0] == 0x90
4
+ end
5
+ def kill
6
+ issue_apdu([0x00, 0x11, 0x00, 0x00, 0x00])[0] == 0x90
7
+ end
8
+ end
@@ -0,0 +1,91 @@
1
+ class Tem::SecAssembler
2
+ def initialize(tem_klass)
3
+ @tem_klass = tem_klass
4
+ @body = []
5
+ @labels = {}
6
+ @lines = {}
7
+ @sp, @ep, @extra_bytes = nil, nil, nil
8
+ end
9
+
10
+ def self.opcode(name, value, *params)
11
+ p_hash = {}
12
+ params.each_index { |i| p_hash[params[i][:name]] = i unless params[i][:name].nil? }
13
+
14
+ define_method(name.to_sym) do |*m_params|
15
+ # linearize the parameters
16
+ param_idx = 0
17
+ s_params = []
18
+ m_params.each_index do |i|
19
+ if m_params[i].instance_of? Hash
20
+ raise "no embedded hashes please! (check parameter #{param_idx})" unless i == m_params.length - 1
21
+ m_params[i].each do |k, v|
22
+ raise "no parameter with name #{k} for opcode #{name}" if p_hash[k].nil?
23
+ raise "parameter #{k} was already assigned a value" unless (param_idx <= p_hash[k] and s_params[p_hash[k]].nil?)
24
+ s_params[p_hash[k]] = v
25
+ end
26
+ else
27
+ s_params[param_idx] = m_params[i]
28
+ param_idx += 1
29
+ end
30
+ end
31
+
32
+ # check for missing parameters
33
+ raise "opcode #{name} requires more parameters" unless s_params.length == params.length and s_params.all? { |v| !v.nil? }
34
+
35
+ # encode parameters
36
+ @lines[@body.length] = Kernel.caller(0)
37
+ @body += @tem_klass.to_tem_ubyte(value)
38
+ s_params.each_index do |i|
39
+ if (s_params[i].kind_of? Numeric) && !params[i][:relative]
40
+ @body += @tem_klass.send "to_tem_#{params[i][:type]}".to_sym, s_params[i]
41
+ else
42
+ @body << { :type => params[i][:type], :relative => params[i][:reladdr] ? params[i][:reladdr] : false }.merge!(
43
+ (s_params[i].kind_of? Numeric) ? { :address => s_params[i].to_i } : { :label => s_params[i].to_sym })
44
+ @body += (@tem_klass.send "to_tem_#{params[i][:type]}".to_sym, 0)[1..-1]
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def assemble(&proc_block)
51
+ # call the block to build the proc
52
+ yield self
53
+
54
+ # link in label addresses
55
+ @body.each_index do |i|
56
+ if @body[i].kind_of? Hash
57
+ raise "label #{@body[i][:label]} undefined" if (!@body[i][:label].nil? and @labels[@body[i][:label]].nil?)
58
+ addr = @body[i][:label].nil? ? @body[i][:address] : @labels[@body[i][:label]]
59
+ q = @body[i][:relative] ? (@tem_klass.send "to_tem_#{@body[i][:type]}_reladdr".to_sym, addr - i - @body[i][:relative]) :
60
+ (@tem_klass.send "to_tem_#{@body[i][:type]}".to_sym, addr)
61
+ @body[i, q.length] = *q
62
+ end
63
+ end
64
+
65
+ return Tem::SecPack.new(:tem_class => @tem_klass, :body => @body, :labels => @labels,
66
+ :ep => @ep || 0, :sp => @sp || @body.length, :extra_bytes => @extra_bytes || 0, :lines => @lines)
67
+ end
68
+
69
+ def label(name)
70
+ raise "label #{name} already defined" unless @labels[name.to_sym].nil?
71
+ @labels[name.to_sym] = @body.length
72
+ end
73
+ def filler(type_name, count = 1)
74
+ bytes = count * @tem_klass.send("tem_#{type_name}_length".to_sym)
75
+ @body += Array.new(bytes, 0)
76
+ end
77
+ def immed(type_name, values)
78
+ values = [values] unless values.instance_of? Array
79
+ @body += values.map { |v| @tem_klass.send "to_tem_#{type_name}".to_sym, v }.flatten
80
+ end
81
+ def entry
82
+ @ep = @body.length
83
+ end
84
+ def stack
85
+ @sp = @body.length
86
+ end
87
+ def extra(extra_bytes)
88
+ @extra_bytes = extra_bytes
89
+ end
90
+ end
91
+