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.
@@ -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
+