tem_ruby 0.14.1 → 0.15.1
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 +4 -0
- data/Manifest +4 -0
- data/dev_ca/config.yml +2 -2
- data/lib/tem/admin/emit.rb +115 -0
- data/lib/tem/admin/migrate.rb +219 -0
- data/lib/tem/apdus/tag.rb +78 -6
- data/lib/tem/benchmarks/benchmarks.rb +1 -1
- data/lib/tem/ca.rb +1 -1
- data/lib/tem/definitions/isa.rb +6 -3
- data/lib/tem/ecert.rb +11 -59
- data/lib/tem/firmware/tc.cap +0 -0
- data/lib/tem/secpack.rb +93 -19
- data/lib/tem/tem.rb +23 -1
- data/lib/tem_ruby.rb +3 -0
- data/tem_ruby.gemspec +5 -5
- data/test/firmware/test_uploader.rb +1 -1
- data/test/tem_unit/test_tem_crypto_keys.rb +45 -22
- data/test/tem_unit/test_tem_crypto_pstore.rb +36 -7
- data/test/tem_unit/test_tem_emit.rb +10 -11
- data/test/tem_unit/test_tem_migrate.rb +43 -0
- data/test/test_driver.rb +1 -12
- data/test/test_tag.rb +42 -0
- metadata +22 -14
data/CHANGELOG
CHANGED
data/Manifest
CHANGED
@@ -14,6 +14,8 @@ dev_ca/ca_cert.pem
|
|
14
14
|
dev_ca/ca_key.pem
|
15
15
|
dev_ca/config.yml
|
16
16
|
lib/tem/_cert.rb
|
17
|
+
lib/tem/admin/emit.rb
|
18
|
+
lib/tem/admin/migrate.rb
|
17
19
|
lib/tem/apdus/buffers.rb
|
18
20
|
lib/tem/apdus/keys.rb
|
19
21
|
lib/tem/apdus/lifecycle.rb
|
@@ -62,9 +64,11 @@ test/tem_unit/test_tem_crypto_random.rb
|
|
62
64
|
test/tem_unit/test_tem_emit.rb
|
63
65
|
test/tem_unit/test_tem_memory.rb
|
64
66
|
test/tem_unit/test_tem_memory_compare.rb
|
67
|
+
test/tem_unit/test_tem_migrate.rb
|
65
68
|
test/tem_unit/test_tem_output.rb
|
66
69
|
test/tem_unit/test_tem_yaml_secpack.rb
|
67
70
|
test/test_auto_conf.rb
|
68
71
|
test/test_crypto_engine.rb
|
69
72
|
test/test_driver.rb
|
70
73
|
test/test_exceptions.rb
|
74
|
+
test/test_tag.rb
|
data/dev_ca/config.yml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
---
|
2
|
-
#
|
2
|
+
# The development CA is valid for 10 years.
|
3
3
|
:ca_validity_days: 3652
|
4
4
|
:issuer:
|
5
5
|
CN: Trusted Execution Module Development CA
|
@@ -8,7 +8,7 @@
|
|
8
8
|
C: US
|
9
9
|
O: Massachusetts Insitute of Technology
|
10
10
|
OU: Computer Science and Artificial Intelligence Laboratory
|
11
|
-
#
|
11
|
+
# A TEM is valid for two years.
|
12
12
|
:ecert_validity_days: 730
|
13
13
|
:subject:
|
14
14
|
CN: Trusted Execution Module DevChip
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Logic for the TEM emission process.
|
2
|
+
#
|
3
|
+
# Author:: Victor Costan
|
4
|
+
# Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
# :nodoc: namespace
|
8
|
+
module Tem::Admin
|
9
|
+
|
10
|
+
|
11
|
+
# Logic for the TEM emission process.
|
12
|
+
module Emit
|
13
|
+
# The SEClosure that performs key generation for the TEM.
|
14
|
+
def self.emit_keygen_seclosure
|
15
|
+
Tem::Assembler.assemble { |s|
|
16
|
+
# Generate Endorsement Key pair, should end up in slots (0, 1).
|
17
|
+
s.genkp :type => 0
|
18
|
+
s.ldbc 1
|
19
|
+
s.sub
|
20
|
+
s.jne :to => :not_ok
|
21
|
+
s.ldbc 0
|
22
|
+
s.sub
|
23
|
+
s.jne :to => :not_ok
|
24
|
+
|
25
|
+
# Generate and output random authorization for PrivEK.
|
26
|
+
s.ldbc 20
|
27
|
+
s.dupn :n => 1
|
28
|
+
s.outnew
|
29
|
+
s.ldwc :privek_auth
|
30
|
+
s.dupn :n => 2
|
31
|
+
s.rnd
|
32
|
+
s.outvb
|
33
|
+
# Set authorizations for PrivEK and PubkEK.
|
34
|
+
s.ldbc 0
|
35
|
+
s.authk :auth => :privek_auth
|
36
|
+
s.ldbc 1 # PubEK always has its initial authorization be all zeroes.
|
37
|
+
s.authk :auth => :pubek_auth
|
38
|
+
s.halt
|
39
|
+
|
40
|
+
# Emitting didn't go well, return nothing and leave.
|
41
|
+
s.label :not_ok
|
42
|
+
s.ldbc 0
|
43
|
+
s.outnew
|
44
|
+
s.halt
|
45
|
+
|
46
|
+
s.label :privek_auth
|
47
|
+
s.zeros :tem_ubyte, 20
|
48
|
+
s.label :pubek_auth
|
49
|
+
s.zeros :tem_ubyte, 20
|
50
|
+
s.stack 4
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
# Performs the key generation step of the TEM emitting process.
|
55
|
+
#
|
56
|
+
# Args:
|
57
|
+
# tem:: session to the TEM that will be emitted
|
58
|
+
#
|
59
|
+
# Returns nil if key generation fails. In case of success, a hash with the
|
60
|
+
# following keys is returned.
|
61
|
+
# :pubek:: the public Endorsement Key (PubEK) -- not stored on the TEM
|
62
|
+
# :privek_auth:: the authentication key for the private Endorsement Key
|
63
|
+
# (PrivEK), which will always be stored on the chip
|
64
|
+
def self.emit_keygen(tem)
|
65
|
+
sec = emit_keygen_seclosure
|
66
|
+
r = tem.execute sec
|
67
|
+
return nil if r.empty?
|
68
|
+
|
69
|
+
privek_auth = r[0...20]
|
70
|
+
pubek_auth = (0...20).map {|i| 0}
|
71
|
+
pubek = tem.tk_read_key 1, pubek_auth
|
72
|
+
tem.tk_delete_key 1, pubek_auth
|
73
|
+
{ :privek_auth => privek_auth, :pubek => pubek }
|
74
|
+
end
|
75
|
+
|
76
|
+
# Drives a TEM though the emit process.
|
77
|
+
#
|
78
|
+
# Args:
|
79
|
+
# tem:: session to the TEM that will be emitted.
|
80
|
+
#
|
81
|
+
# Returns nil if the emit process fails (most likely, the TEM was already
|
82
|
+
# emitted). If the process completes, a hash with the following keys is
|
83
|
+
# returned.
|
84
|
+
# :privek_auth:: the authorization token for the private Endorsement Key
|
85
|
+
# (PrivEK) -- this value should be handled with care
|
86
|
+
def self.emit(tem)
|
87
|
+
tag = {}
|
88
|
+
|
89
|
+
return nil unless key_data = emit_keygen(tem)
|
90
|
+
|
91
|
+
# Build the Endorsement Certificate.
|
92
|
+
ecert = Tem::CA.new_ecert key_data[:pubek].ssl_key
|
93
|
+
tag.merge! Tem::ECert.ecert_tag ecert
|
94
|
+
|
95
|
+
# Build administrative SECpacks.
|
96
|
+
tag.merge! Tem::Admin::Migrate.tag_data key_data[:pubek],
|
97
|
+
key_data[:privek_auth]
|
98
|
+
|
99
|
+
tem.set_tag tag
|
100
|
+
key_data
|
101
|
+
end
|
102
|
+
|
103
|
+
# Emits the TEM.
|
104
|
+
#
|
105
|
+
# Returns nil if the emit process fails (most likely, the TEM was already
|
106
|
+
# emitted). If the process completes, it returns the authorization token for
|
107
|
+
# the private Endorsement Key (PrivEK). This value is very sensitive and its
|
108
|
+
# disclosure will compromise the TEM.
|
109
|
+
def emit
|
110
|
+
emit_data = Tem::Admin::Emit.emit self
|
111
|
+
emit_data and emit_data[:privek_auth]
|
112
|
+
end
|
113
|
+
end # module Tem::Admin::Emit
|
114
|
+
|
115
|
+
end # namespace Tem::Admin
|
@@ -0,0 +1,219 @@
|
|
1
|
+
# Logic for SECpack migration.
|
2
|
+
#
|
3
|
+
# Author:: Victor Costan
|
4
|
+
# Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'openssl'
|
8
|
+
|
9
|
+
# :nodoc: namespace
|
10
|
+
module Tem::Admin
|
11
|
+
|
12
|
+
|
13
|
+
# Logic for migrating SECpacks.
|
14
|
+
module Migrate
|
15
|
+
# SEClosure that verifies the destination TEM's ECert.
|
16
|
+
#
|
17
|
+
# Args:
|
18
|
+
# key_ps_addr:: the PStore address used to store the TEM key's ID
|
19
|
+
# authz:: the authentication secret for the TEM's PrivEK
|
20
|
+
def self.ecert_verify_seclosure(key_ps_addr, authz)
|
21
|
+
Tem::Assembler.assemble { |s|
|
22
|
+
# TODO: some actual verification, jump to :failure if it doesn't work
|
23
|
+
|
24
|
+
s.ldwc :const => :pubek
|
25
|
+
s.rdk
|
26
|
+
s.authk :auth => :authz
|
27
|
+
s.stw :to => :key_id
|
28
|
+
s.pswrfxb :addr => :pstore_addr, :from => :key_id
|
29
|
+
s.label :success
|
30
|
+
s.ldbc :const => 1
|
31
|
+
s.dupn :n => 1
|
32
|
+
s.outnew
|
33
|
+
s.outb
|
34
|
+
s.halt
|
35
|
+
|
36
|
+
s.label :failure
|
37
|
+
s.ldbc :const => 1
|
38
|
+
s.outnew
|
39
|
+
s.ldbc :const => 0
|
40
|
+
s.outb
|
41
|
+
s.halt
|
42
|
+
|
43
|
+
s.label :key_id
|
44
|
+
s.zeros :tem_ps_value # Will hold the ID of the loaded PubEK.
|
45
|
+
|
46
|
+
s.label :secret
|
47
|
+
s.label :authz # The authentication key for the PrivEK.
|
48
|
+
s.data :tem_ubyte, authz
|
49
|
+
s.label :pstore_addr
|
50
|
+
s.data :tem_ps_addr, key_ps_addr
|
51
|
+
s.label :plain
|
52
|
+
# ARG: the target TEM's public endorsement key.
|
53
|
+
s.label :pubek
|
54
|
+
s.zeros :tem_ubyte, 300
|
55
|
+
# ARG: the target TEM's endorsement certificate.
|
56
|
+
s.label :ecert
|
57
|
+
s.stack 10
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
# Blank version of the SEClosure that verifies the destination TEM's ECert.
|
62
|
+
#
|
63
|
+
# The returned SEClosure is not suitable for execution. Its encrypted bytes
|
64
|
+
# should be replaced with the bytes from a SECpack generated with live data.
|
65
|
+
def self.blank_ecert_verify_seclosure
|
66
|
+
ecert_verify_seclosure [0] * Tem::Abi.tem_ps_addr_length,
|
67
|
+
[0] * Tem::Abi.tem_hash_length
|
68
|
+
end
|
69
|
+
|
70
|
+
# SEClosure that migrates a SECpack.
|
71
|
+
#
|
72
|
+
# Args:
|
73
|
+
# key_ps_addr:: the PStore address used to store the TEM key's ID
|
74
|
+
# authz:: the authentication secret for the TEM's PrivEK
|
75
|
+
def self.migrate_seclosure(key_ps_addr, authz)
|
76
|
+
Tem::Assembler.assemble { |s|
|
77
|
+
s.ldbc :const => 0 # Authorize PrivEK.
|
78
|
+
s.authk :auth => :authz
|
79
|
+
s.dupn :n => 1 # Compute the size of the encrypted blob.
|
80
|
+
s.ldw :from => :secpack_secret_size
|
81
|
+
s.ldkel
|
82
|
+
|
83
|
+
# Decrypt secpack.
|
84
|
+
s.ldwc :const => :secpack_encrypted
|
85
|
+
s.ldwc :const => :secpack_encrypted
|
86
|
+
s.kdvb
|
87
|
+
s.ldw :from => :secpack_secret_size # Fail for wrong blob size.
|
88
|
+
s.sub
|
89
|
+
s.jnz :failure
|
90
|
+
|
91
|
+
# Authorize target PubEK.
|
92
|
+
s.psrdfxb :addr => :pstore_addr, :to => :key_id
|
93
|
+
s.ldw :from => :key_id
|
94
|
+
s.authk :auth => :authz
|
95
|
+
|
96
|
+
s.dupn :n => 1 # Prepare output buffer.
|
97
|
+
s.ldw :from => :secpack_secret_size
|
98
|
+
s.ldkel
|
99
|
+
s.outnew
|
100
|
+
|
101
|
+
s.ldw :from => :secpack_secret_size # Re-encrypt the blob.
|
102
|
+
s.ldwc :const => :secpack_encrypted
|
103
|
+
s.ldwc :const => -1
|
104
|
+
s.kevb
|
105
|
+
|
106
|
+
s.ldw :from => :key_id # Clean up.
|
107
|
+
s.relk
|
108
|
+
s.ldbc :const => -1
|
109
|
+
s.stw :to => :key_id
|
110
|
+
s.pswrfxb :addr => :pstore_addr, :from => :key_id
|
111
|
+
s.halt
|
112
|
+
|
113
|
+
s.label :failure # Communicate some failure.
|
114
|
+
s.ldbc :const => 0
|
115
|
+
s.outnew
|
116
|
+
s.halt
|
117
|
+
|
118
|
+
s.label :key_id
|
119
|
+
s.zeros :tem_ps_value # Will hold the ID of the loaded PubEK.
|
120
|
+
|
121
|
+
s.label :secret
|
122
|
+
s.label :authz # The authentication key for the PrivEK.
|
123
|
+
s.data :tem_ubyte, authz
|
124
|
+
s.label :pstore_addr
|
125
|
+
s.data :tem_ps_addr, key_ps_addr
|
126
|
+
s.label :plain
|
127
|
+
s.stack 20
|
128
|
+
# ARG: the 'encrypted size' field in the SECpack header.
|
129
|
+
s.label :secpack_secret_size
|
130
|
+
s.zeros :tem_short, 1
|
131
|
+
# ARG: the encrypted blob in the SECpack.
|
132
|
+
s.label :secpack_encrypted
|
133
|
+
s.zeros :tem_ubyte, 1
|
134
|
+
s.label :secpack_encrypted_end
|
135
|
+
}
|
136
|
+
end
|
137
|
+
|
138
|
+
# Blank version of the SEClosure that verifies the destination TEM's ECert.
|
139
|
+
#
|
140
|
+
# The returned SEClosure is not suitable for execution. Its encrypted bytes
|
141
|
+
# should be replaced with the bytes from a SECpack generated with live data.
|
142
|
+
def self.blank_migrate_seclosure
|
143
|
+
migrate_seclosure [0] * Tem::Abi.tem_ps_addr_length,
|
144
|
+
[0] * Tem::Abi.tem_hash_length
|
145
|
+
end
|
146
|
+
|
147
|
+
# The key storing the encrypted bytes of the ecert_verify SECpack in the
|
148
|
+
# TEM's tag.
|
149
|
+
def self.ecert_verify_bytes_tag_key
|
150
|
+
0x11
|
151
|
+
end
|
152
|
+
|
153
|
+
# The key storing the encrypted bytes of the migrate SECpack in the TEM's tag.
|
154
|
+
def self.migrate_bytes_tag_key
|
155
|
+
0x12
|
156
|
+
end
|
157
|
+
|
158
|
+
# Data to be included in a TEM's tag to support migration.
|
159
|
+
#
|
160
|
+
# Returns a hash of tag key-values to be included in the TEM's tag during
|
161
|
+
# emission.
|
162
|
+
def self.tag_data(pubek, privek_authz)
|
163
|
+
ps_addr = OpenSSL::Random.random_bytes(Tem::Abi.tem_ps_addr_length).
|
164
|
+
unpack('C*')
|
165
|
+
ev_sec = ecert_verify_seclosure ps_addr, privek_authz
|
166
|
+
ev_sec.bind pubek
|
167
|
+
|
168
|
+
m_sec = migrate_seclosure ps_addr, privek_authz
|
169
|
+
m_sec.bind pubek
|
170
|
+
|
171
|
+
{
|
172
|
+
ecert_verify_bytes_tag_key => ev_sec.encrypted_data,
|
173
|
+
migrate_bytes_tag_key => m_sec.encrypted_data
|
174
|
+
}
|
175
|
+
end
|
176
|
+
|
177
|
+
# Recovers the migration-related SECpacks from the TEM's tag data.
|
178
|
+
def self.seclosures_from_tag_data(tem)
|
179
|
+
tag_data = tem.tag
|
180
|
+
|
181
|
+
ecert_verify = blank_ecert_verify_seclosure
|
182
|
+
ecert_verify.fake_bind
|
183
|
+
ecert_verify.encrypted_data = tag_data[ecert_verify_bytes_tag_key]
|
184
|
+
|
185
|
+
migrate = blank_migrate_seclosure
|
186
|
+
migrate.fake_bind
|
187
|
+
migrate.encrypted_data = tag_data[migrate_bytes_tag_key]
|
188
|
+
|
189
|
+
{ :ecert_verify => ecert_verify, :migrate => migrate }
|
190
|
+
end
|
191
|
+
|
192
|
+
# Migrates a SECpack to another TEM.
|
193
|
+
#
|
194
|
+
# Args:
|
195
|
+
# secpack:: the SECpack to be migrated
|
196
|
+
# ecert:: the Endorsement Certificate of the destination TEM
|
197
|
+
#
|
198
|
+
# Returns the migrated SECpack, or nil if the Endorsement Certificate was
|
199
|
+
# rejected.
|
200
|
+
def migrate(secpack, ecert)
|
201
|
+
migrated = secpack.copy
|
202
|
+
secpacks = Tem::Admin::Migrate.seclosures_from_tag_data self
|
203
|
+
|
204
|
+
verify = secpacks[:ecert_verify]
|
205
|
+
verify.set_bytes :pubek,
|
206
|
+
Tem::Key.new_from_ssl_key(ecert.public_key).to_tem_key
|
207
|
+
return nil if execute(verify) != [1]
|
208
|
+
|
209
|
+
migrate = secpacks[:migrate]
|
210
|
+
migrate.set_value :secpack_secret_size, :tem_short, secpack.secret_bytes +
|
211
|
+
Tem::Abi.tem_hash_length
|
212
|
+
migrate.set_bytes :secpack_encrypted, migrated.encrypted_data
|
213
|
+
return nil unless new_encrypted_data = execute(migrate)
|
214
|
+
migrated.encrypted_data = new_encrypted_data
|
215
|
+
migrated
|
216
|
+
end
|
217
|
+
end # module Tem::Admin::Migrate
|
218
|
+
|
219
|
+
end # namespace Tem::Admin
|
data/lib/tem/apdus/tag.rb
CHANGED
@@ -9,7 +9,15 @@ module Tem::Apdus
|
|
9
9
|
|
10
10
|
|
11
11
|
module Tag
|
12
|
-
|
12
|
+
# Writes an array of bytes to the TEM's tag.
|
13
|
+
#
|
14
|
+
# The TEM's tag can only be written once, when the TEM is emitted.
|
15
|
+
#
|
16
|
+
# Args:
|
17
|
+
# tag_data:: the array of bytes to write to the TEM's tag
|
18
|
+
#
|
19
|
+
# The return value is unspecified.
|
20
|
+
def set_raw_tag_data(tag_data)
|
13
21
|
buffer_id = post_buffer tag_data
|
14
22
|
begin
|
15
23
|
@transport.iso_apdu! :ins => 0x30, :p1 => buffer_id
|
@@ -18,12 +26,22 @@ module Tag
|
|
18
26
|
end
|
19
27
|
end
|
20
28
|
|
21
|
-
|
29
|
+
# The number of bytes in the TEM's tag.
|
30
|
+
#
|
31
|
+
# This method issues an APDU when it's called (i.e. no caching is done).
|
32
|
+
def get_raw_tag_length
|
22
33
|
response = @transport.iso_apdu! :ins => 0x31
|
23
34
|
return read_tem_short(response, 0)
|
24
35
|
end
|
25
36
|
|
26
|
-
|
37
|
+
# Reads raw bytes in the TEM's tag.
|
38
|
+
#
|
39
|
+
# Args:
|
40
|
+
# offset:: the offset of the first byte to be read from the TEM's tag
|
41
|
+
# length:: the number of bytes to be read from the TEM's tag.
|
42
|
+
#
|
43
|
+
# Returns an array of bytes containing the requested TEM tag data.
|
44
|
+
def get_raw_tag_data(offset, length)
|
27
45
|
buffer_id = alloc_buffer length
|
28
46
|
begin
|
29
47
|
@transport.iso_apdu! :ins => 0x32, :p1 => buffer_id,
|
@@ -36,9 +54,63 @@ module Tag
|
|
36
54
|
tag_data
|
37
55
|
end
|
38
56
|
|
39
|
-
|
40
|
-
|
41
|
-
|
57
|
+
# Encodes structured tag data into raw TLV tag data.
|
58
|
+
#
|
59
|
+
# Args:
|
60
|
+
# data:: a hash whose keys are numbers (tag keys), and whose values are
|
61
|
+
# arrays of bytes (values associated with the tag keys)
|
62
|
+
#
|
63
|
+
# Returns an array of bytes with the raw data.
|
64
|
+
def self.encode_tag(data)
|
65
|
+
data.keys.sort.map { |key|
|
66
|
+
value = data[key]
|
67
|
+
[Tem::Abi.to_tem_ubyte(key), Tem::Abi.to_tem_short(value.length), value]
|
68
|
+
}.flatten
|
69
|
+
end
|
70
|
+
|
71
|
+
# Decodes raw TLV tag data into its structured form.
|
72
|
+
#
|
73
|
+
# Args:
|
74
|
+
# raw_data:: an array of bytes containing the raw data in the TEM tag
|
75
|
+
#
|
76
|
+
# Returns a hash whose keys are numbers (tag keys), and whose values are
|
77
|
+
# arrays of bytes (values associated with the tag keys).
|
78
|
+
def self.decode_tag(raw_data)
|
79
|
+
data = {}
|
80
|
+
index = 0
|
81
|
+
while index < raw_data.length
|
82
|
+
key = Tem::Abi.read_tem_ubyte raw_data, index
|
83
|
+
value_length = Tem::Abi.read_tem_short raw_data, index + 1
|
84
|
+
data[key] = raw_data[index + 3, value_length]
|
85
|
+
index += 3 + value_length
|
86
|
+
end
|
87
|
+
data
|
88
|
+
end
|
89
|
+
|
90
|
+
# Writes an structured data to the TEM's tag.
|
91
|
+
#
|
92
|
+
# The TEM's tag can only be written once, when the TEM is emitted.
|
93
|
+
#
|
94
|
+
# Args:
|
95
|
+
# tag_data:: the array of bytes to write to the TEM's tag
|
96
|
+
#
|
97
|
+
# The return value is unspecified.
|
98
|
+
def set_tag(data)
|
99
|
+
raw_data = Tem::Apdus::Tag.encode_tag data
|
100
|
+
set_raw_tag_data raw_data
|
101
|
+
icache[:tag] = Tem::Apdus::Tag.decode_tag raw_data
|
102
|
+
end
|
103
|
+
|
104
|
+
# The TEM's tag data.
|
105
|
+
#
|
106
|
+
# Returns a hash whose keys are numbers (tag keys), and whose values are
|
107
|
+
# arrays of bytes (values associated with the tag keys). The result of this
|
108
|
+
# method is cached.
|
109
|
+
def tag
|
110
|
+
return icache[:tag] if icache[:tag]
|
111
|
+
|
112
|
+
raw_tag_data = get_raw_tag_data 0, get_raw_tag_length
|
113
|
+
icache[:tag] = Tem::Apdus::Tag.decode_tag raw_tag_data
|
42
114
|
end
|
43
115
|
end
|
44
116
|
|
@@ -64,7 +64,7 @@ class Tem::Benchmarks
|
|
64
64
|
benchmarks = {}
|
65
65
|
t = Tem::Benchmarks.new
|
66
66
|
t.setup
|
67
|
-
t.methods.select { |m| m =~ /time_/ }.each do |m|
|
67
|
+
t.methods.select { |m| m =~ /time_/ }.sort.each do |m|
|
68
68
|
print "Timing: #{m[5..-1]}...\n"
|
69
69
|
t.send m.to_sym
|
70
70
|
benchmarks[m] = t.timing
|
data/lib/tem/ca.rb
CHANGED
@@ -4,7 +4,7 @@ require 'yaml'
|
|
4
4
|
# Certificate Authority (CA) functionality for TEM manufacturers
|
5
5
|
module Tem::CA
|
6
6
|
# Creates an Endorsement Certificate for a TEM's Public Endorsement Key.
|
7
|
-
def new_ecert(pubek)
|
7
|
+
def self.new_ecert(pubek)
|
8
8
|
ca_cert = Tem::CA.ca_cert
|
9
9
|
ca_key = Tem::CA.ca_key
|
10
10
|
conf = Tem::CA.config
|
data/lib/tem/definitions/isa.rb
CHANGED
@@ -190,13 +190,16 @@ module Tem::Isa
|
|
190
190
|
isa.instruction 0x46, :halt
|
191
191
|
# 1 ST -> 0 ST
|
192
192
|
isa.instruction 0x47, :psrm
|
193
|
-
|
193
|
+
|
194
|
+
# 2 ST -> 1 ST
|
195
|
+
isa.instruction 0x58, :ldkel
|
194
196
|
# 1 ST -> 1 ST
|
195
|
-
isa.instruction 0x5A, :rdk
|
197
|
+
isa.instruction 0x5A, :rdk
|
196
198
|
# 1 ST -> 0 ST
|
197
199
|
isa.instruction 0x5C, :relk
|
198
|
-
|
200
|
+
# 1 ST -> 1 ST
|
199
201
|
isa.instruction 0x5D, :ldkl
|
202
|
+
|
200
203
|
# 1 IM_B -> 2 ST
|
201
204
|
isa.instruction 0x5E, :genkp, {:name => :type, :type => :tem_ubyte }
|
202
205
|
# 1 ST, 1 IM -> 1 ST
|
data/lib/tem/ecert.rb
CHANGED
@@ -1,14 +1,20 @@
|
|
1
1
|
require 'openssl'
|
2
2
|
|
3
3
|
module Tem::ECert
|
4
|
-
#
|
5
|
-
def
|
6
|
-
|
4
|
+
# The key storing the Endorsement Certificate in the TEM's tag.
|
5
|
+
def self.ecert_tag_key
|
6
|
+
0x01
|
7
|
+
end
|
8
|
+
|
9
|
+
# The tag contents for an endorsement certificate.
|
10
|
+
def self.ecert_tag(ecert)
|
11
|
+
{ ecert_tag_key => ecert.to_der.unpack('C*') }
|
7
12
|
end
|
8
13
|
|
9
14
|
# Retrieves the TEM's Endorsement Certificate.
|
10
15
|
def endorsement_cert
|
11
|
-
|
16
|
+
raw_cert = tag[Tem::ECert.ecert_tag_key].pack('C*')
|
17
|
+
OpenSSL::X509::Certificate.new raw_cert
|
12
18
|
end
|
13
19
|
|
14
20
|
# Retrieves the certificate of the TEM's Manfacturer (CA).
|
@@ -19,59 +25,5 @@ module Tem::ECert
|
|
19
25
|
# Retrieves the TEM's Public Endorsement Key.
|
20
26
|
def pubek
|
21
27
|
Tem::Key.new_from_ssl_key endorsement_cert.public_key
|
22
|
-
end
|
23
|
-
|
24
|
-
# Drives a TEM though the emitting process.
|
25
|
-
def emit
|
26
|
-
emit_sec = assemble do |s|
|
27
|
-
# Generate Endorsement Key pair, should end up in slots (0, 1).
|
28
|
-
s.genkp :type => 0
|
29
|
-
s.ldbc 1
|
30
|
-
s.sub
|
31
|
-
s.jne :to => :not_ok
|
32
|
-
s.ldbc 0
|
33
|
-
s.sub
|
34
|
-
s.jne :to => :not_ok
|
35
|
-
|
36
|
-
# Generate and output random authorization for PrivEK.
|
37
|
-
s.ldbc 20
|
38
|
-
s.dupn :n => 1
|
39
|
-
s.outnew
|
40
|
-
s.ldwc :privek_auth
|
41
|
-
s.dupn :n => 2
|
42
|
-
s.rnd
|
43
|
-
s.outvb
|
44
|
-
# Set authorizations for PrivEK and PubkEK.
|
45
|
-
s.ldbc 0
|
46
|
-
s.authk :auth => :privek_auth
|
47
|
-
s.ldbc 1 # PubEK always has its initial authorization be all zeroes.
|
48
|
-
s.authk :auth => :pubek_auth
|
49
|
-
s.halt
|
50
|
-
|
51
|
-
# Emitting didn't go well, return nothing and leave.
|
52
|
-
s.label :not_ok
|
53
|
-
s.ldbc 0
|
54
|
-
s.outnew
|
55
|
-
s.halt
|
56
|
-
|
57
|
-
s.label :privek_auth
|
58
|
-
s.zeros :tem_ubyte, 20
|
59
|
-
s.label :pubek_auth
|
60
|
-
s.zeros :tem_ubyte, 20
|
61
|
-
s.stack 4
|
62
|
-
end
|
63
|
-
|
64
|
-
r = execute emit_sec
|
65
|
-
if r.length == 0
|
66
|
-
return nil
|
67
|
-
else
|
68
|
-
privk_auth = r[0...20]
|
69
|
-
pubek_auth = (0...20).map {|i| 0}
|
70
|
-
pubek = tk_read_key 1, pubek_auth
|
71
|
-
tk_delete_key 1, pubek_auth
|
72
|
-
ecert = new_ecert pubek.ssl_key
|
73
|
-
set_ecert ecert
|
74
|
-
return { :privek_auth => privk_auth }
|
75
|
-
end
|
76
|
-
end
|
28
|
+
end
|
77
29
|
end
|
data/lib/tem/firmware/tc.cap
CHANGED
Binary file
|
data/lib/tem/secpack.rb
CHANGED
@@ -2,7 +2,7 @@ require 'yaml'
|
|
2
2
|
|
3
3
|
class Tem::SecPack
|
4
4
|
@@serialized_ivars = [:body, :labels, :ep, :sp, :extra_bytes, :signed_bytes,
|
5
|
-
:
|
5
|
+
:secret_bytes, :bound, :lines]
|
6
6
|
|
7
7
|
def self.new_from_array(array)
|
8
8
|
arg_hash = { }
|
@@ -14,6 +14,11 @@ class Tem::SecPack
|
|
14
14
|
array = YAML.load yaml_str
|
15
15
|
new_from_array array
|
16
16
|
end
|
17
|
+
|
18
|
+
# Creates a deep copy of the SECpack.
|
19
|
+
def copy
|
20
|
+
Tem::SecPack.new_from_array self.to_array
|
21
|
+
end
|
17
22
|
|
18
23
|
def to_array
|
19
24
|
@@serialized_ivars.map { |m| self.instance_variable_get :"@#{m}" }
|
@@ -23,7 +28,13 @@ class Tem::SecPack
|
|
23
28
|
self.to_array.to_yaml.to_s
|
24
29
|
end
|
25
30
|
|
26
|
-
|
31
|
+
# The size of the secret data in the SECpack.
|
32
|
+
attr_reader :secret_bytes
|
33
|
+
# The SECpack's body.
|
34
|
+
attr_reader :body
|
35
|
+
# The size of the encrypted data, if the SECpack is bound. False otherwise.
|
36
|
+
attr_reader :bound
|
37
|
+
# Debugging information.
|
27
38
|
attr_reader :lines
|
28
39
|
|
29
40
|
def trim_extra_bytes
|
@@ -51,37 +62,100 @@ class Tem::SecPack
|
|
51
62
|
def label_address(label_name)
|
52
63
|
@labels[label_name.to_sym]
|
53
64
|
end
|
65
|
+
|
66
|
+
def bind(public_key, secret_from = :secret, plain_from = :plain)
|
67
|
+
raise "SECpack is already bound" if @bound
|
54
68
|
|
55
|
-
def bind(public_key, encrypt_from = 0, plaintext_from = 0)
|
56
69
|
expand_extra_bytes
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
70
|
+
unless secret_from.kind_of? Numeric
|
71
|
+
secret_from_label = secret_from
|
72
|
+
secret_from = @labels[secret_from.to_sym]
|
73
|
+
raise "Undefined label #{secret_from_label}" unless secret_from
|
74
|
+
end
|
75
|
+
unless plain_from.kind_of? Numeric
|
76
|
+
plain_from_label = plain_from
|
77
|
+
plain_from = @labels[plain_from.to_sym]
|
78
|
+
raise "Undefined label #{plain_from_label}" unless plain_from
|
79
|
+
end
|
62
80
|
|
63
|
-
|
64
|
-
|
65
|
-
|
81
|
+
@signed_bytes = secret_from
|
82
|
+
@secret_bytes = plain_from - secret_from
|
83
|
+
|
84
|
+
secpack_sig = Tem::Abi.tem_hash tem_header + @body[0, plain_from]
|
85
|
+
crypt = public_key.encrypt @body[secret_from, @secret_bytes] + secpack_sig
|
86
|
+
@body = [@body[0, secret_from], crypt, @body[plain_from..-1]].flatten
|
66
87
|
|
67
|
-
label_delta = crypt.length - @
|
88
|
+
label_delta = crypt.length - @secret_bytes
|
89
|
+
relocate_labels secret_from, plain_from, label_delta
|
90
|
+
|
91
|
+
#trim_extra_bytes
|
92
|
+
@bound = crypt.length
|
93
|
+
end
|
94
|
+
|
95
|
+
def fake_bind(secret_from = :secret, plain_from = :plain)
|
96
|
+
raise "SECpack is already bound" if @bound
|
97
|
+
|
98
|
+
expand_extra_bytes
|
99
|
+
unless secret_from.kind_of? Numeric
|
100
|
+
secret_from_label = secret_from
|
101
|
+
secret_from = @labels[secret_from.to_sym]
|
102
|
+
raise "Undefined label #{secret_from_label}" unless secret_from
|
103
|
+
end
|
104
|
+
unless plain_from.kind_of? Numeric
|
105
|
+
plain_from_label = plain_from
|
106
|
+
plain_from = @labels[plain_from.to_sym]
|
107
|
+
raise "Undefined label #{plain_from_label}" unless plain_from
|
108
|
+
end
|
109
|
+
|
110
|
+
@signed_bytes = secret_from
|
111
|
+
@secret_bytes = plain_from - secret_from
|
112
|
+
|
113
|
+
#trim_extra_bytes
|
114
|
+
@bound = @secret_bytes
|
115
|
+
end
|
116
|
+
|
117
|
+
# Relocates the labels to reflect a change in the size of encrypted bytes.
|
118
|
+
#
|
119
|
+
# Args:
|
120
|
+
# same_until:: the end of the signed area (no relocations done there)
|
121
|
+
# delete_until:: the end of the old encrypted area (labels are removed)
|
122
|
+
# delta:: the size difference between the new and the old encrypted areas
|
123
|
+
def relocate_labels(same_until, delete_until, delta)
|
68
124
|
@labels = Hash[*(@labels.map { |k, v|
|
69
|
-
if v
|
125
|
+
if v <= same_until
|
70
126
|
[k, v]
|
71
|
-
elsif v <
|
127
|
+
elsif v < delete_until
|
72
128
|
[]
|
73
129
|
else
|
74
|
-
[k, v +
|
130
|
+
[k, v + delta]
|
75
131
|
end
|
76
|
-
}.flatten)]
|
132
|
+
}.flatten)]
|
133
|
+
end
|
77
134
|
|
78
|
-
|
79
|
-
|
135
|
+
# The encrypted data in a SECpack.
|
136
|
+
#
|
137
|
+
# This is useful for SECpack migration -- the encrypted bytes are the only
|
138
|
+
# part that has to be migrated.
|
139
|
+
def encrypted_data
|
140
|
+
@body[@signed_bytes, @bound]
|
141
|
+
end
|
142
|
+
|
143
|
+
# Replaces the encrypted bytes in a SECpack.
|
144
|
+
#
|
145
|
+
# This is used in SECpack migration -- the encryption bytes are the only part
|
146
|
+
# that changes during migration.
|
147
|
+
def encrypted_data=(new_encrypted_bytes)
|
148
|
+
raise "SECpack is not bound. See #bind and #fake_bind." unless @bound
|
149
|
+
|
150
|
+
@body[@signed_bytes, @bound] = new_encrypted_bytes
|
151
|
+
relocate_labels @signed_bytes, @signed_bytes + @bound,
|
152
|
+
new_encrypted_bytes.length - @bound
|
153
|
+
@bound = new_encrypted_bytes.length
|
80
154
|
end
|
81
155
|
|
82
156
|
def tem_header
|
83
157
|
# TODO: use 0x0100 (no tracing) depending on options
|
84
|
-
hh = [0x0101, @signed_bytes || 0, @
|
158
|
+
hh = [0x0101, @signed_bytes || 0, @secret_bytes || 0, @extra_bytes, @sp,
|
85
159
|
@ep].map { |n| Tem::Abi.to_tem_ushort n }.flatten
|
86
160
|
hh += Array.new((Tem::Abi.tem_hash [0]).length - hh.length, 0)
|
87
161
|
return hh
|
data/lib/tem/tem.rb
CHANGED
@@ -5,6 +5,9 @@ class Tem::Session
|
|
5
5
|
include Tem::Apdus::Lifecycle
|
6
6
|
include Tem::Apdus::Tag
|
7
7
|
|
8
|
+
include Tem::Admin::Emit
|
9
|
+
include Tem::Admin::Migrate
|
10
|
+
|
8
11
|
include Tem::CA
|
9
12
|
include Tem::ECert
|
10
13
|
include Tem::SeClosures
|
@@ -12,20 +15,39 @@ class Tem::Session
|
|
12
15
|
|
13
16
|
CAPPLET_AID = [0x19, 0x83, 0x12, 0x29, 0x10, 0xBA, 0xBE]
|
14
17
|
|
18
|
+
# The transport used for this TEM.
|
15
19
|
attr_reader :transport
|
16
20
|
|
21
|
+
# The TEM instance cache.
|
22
|
+
#
|
23
|
+
# This cache stores information about the TEM connected to this session. The
|
24
|
+
# cache can be safely cleared without losing correctness.
|
25
|
+
#
|
26
|
+
# The cache should not be modified directly by client code.
|
27
|
+
attr_reader :icache
|
28
|
+
|
17
29
|
def initialize(transport)
|
18
30
|
@transport = transport
|
19
31
|
@transport.extend Smartcard::Gp::GpCardMixin
|
20
32
|
@transport.select_application CAPPLET_AID
|
33
|
+
|
34
|
+
@icache = {}
|
21
35
|
end
|
22
|
-
|
36
|
+
|
23
37
|
def disconnect
|
24
38
|
return unless @transport
|
25
39
|
@transport.disconnect
|
26
40
|
@transport = nil
|
41
|
+
clear_icache
|
27
42
|
end
|
28
43
|
|
44
|
+
# Clears the TEM instance cache.
|
45
|
+
#
|
46
|
+
# This should be called when connecting to a different TEM.
|
47
|
+
def clear_icache
|
48
|
+
@icache.clear
|
49
|
+
end
|
50
|
+
|
29
51
|
def tem_secpack_error(response)
|
30
52
|
raise "TEM refused the SECpack"
|
31
53
|
end
|
data/lib/tem_ruby.rb
CHANGED
data/tem_ruby.gemspec
CHANGED
@@ -2,23 +2,23 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{tem_ruby}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.15.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Victor Costan"]
|
9
|
-
s.date = %q{2009-11-
|
9
|
+
s.date = %q{2009-11-18}
|
10
10
|
s.description = %q{TEM (Trusted Execution Module) driver, written in and for ruby.}
|
11
11
|
s.email = %q{victor@costan.us}
|
12
12
|
s.executables = ["tem_bench", "tem_ca", "tem_irb", "tem_proxy", "tem_stat", "tem_upload_fw"]
|
13
|
-
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "bin/tem_bench", "bin/tem_ca", "bin/tem_irb", "bin/tem_proxy", "bin/tem_stat", "bin/tem_upload_fw", "lib/tem/_cert.rb", "lib/tem/apdus/buffers.rb", "lib/tem/apdus/keys.rb", "lib/tem/apdus/lifecycle.rb", "lib/tem/apdus/tag.rb", "lib/tem/auto_conf.rb", "lib/tem/benchmarks/benchmarks.rb", "lib/tem/benchmarks/blank_bound_secpack.rb", "lib/tem/benchmarks/blank_sec.rb", "lib/tem/benchmarks/devchip_decrypt.rb", "lib/tem/benchmarks/post_buffer.rb", "lib/tem/benchmarks/simple_apdu.rb", "lib/tem/benchmarks/vm_perf.rb", "lib/tem/benchmarks/vm_perf_bound.rb", "lib/tem/builders/abi.rb", "lib/tem/builders/assembler.rb", "lib/tem/builders/crypto.rb", "lib/tem/builders/isa.rb", "lib/tem/ca.rb", "lib/tem/definitions/abi.rb", "lib/tem/definitions/assembler.rb", "lib/tem/definitions/isa.rb", "lib/tem/ecert.rb", "lib/tem/firmware/tc.cap", "lib/tem/firmware/uploader.rb", "lib/tem/hive.rb", "lib/tem/keys/asymmetric.rb", "lib/tem/keys/key.rb", "lib/tem/keys/symmetric.rb", "lib/tem/sec_exec_error.rb", "lib/tem/seclosures.rb", "lib/tem/secpack.rb", "lib/tem/tem.rb", "lib/tem/toolkit.rb", "lib/tem_ruby.rb"]
|
14
|
-
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README", "Rakefile", "bin/tem_bench", "bin/tem_ca", "bin/tem_irb", "bin/tem_proxy", "bin/tem_stat", "bin/tem_upload_fw", "dev_ca/ca_cert.cer", "dev_ca/ca_cert.pem", "dev_ca/ca_key.pem", "dev_ca/config.yml", "lib/tem/_cert.rb", "lib/tem/apdus/buffers.rb", "lib/tem/apdus/keys.rb", "lib/tem/apdus/lifecycle.rb", "lib/tem/apdus/tag.rb", "lib/tem/auto_conf.rb", "lib/tem/benchmarks/benchmarks.rb", "lib/tem/benchmarks/blank_bound_secpack.rb", "lib/tem/benchmarks/blank_sec.rb", "lib/tem/benchmarks/devchip_decrypt.rb", "lib/tem/benchmarks/post_buffer.rb", "lib/tem/benchmarks/simple_apdu.rb", "lib/tem/benchmarks/vm_perf.rb", "lib/tem/benchmarks/vm_perf_bound.rb", "lib/tem/builders/abi.rb", "lib/tem/builders/assembler.rb", "lib/tem/builders/crypto.rb", "lib/tem/builders/isa.rb", "lib/tem/ca.rb", "lib/tem/definitions/abi.rb", "lib/tem/definitions/assembler.rb", "lib/tem/definitions/isa.rb", "lib/tem/ecert.rb", "lib/tem/firmware/tc.cap", "lib/tem/firmware/uploader.rb", "lib/tem/hive.rb", "lib/tem/keys/asymmetric.rb", "lib/tem/keys/key.rb", "lib/tem/keys/symmetric.rb", "lib/tem/sec_exec_error.rb", "lib/tem/seclosures.rb", "lib/tem/secpack.rb", "lib/tem/tem.rb", "lib/tem/toolkit.rb", "lib/tem_ruby.rb", "test/_test_cert.rb", "test/builders/test_abi_builder.rb", "test/firmware/test_uploader.rb", "test/tem_test_case.rb", "test/tem_unit/test_tem_alu.rb", "test/tem_unit/test_tem_bound_secpack.rb", "test/tem_unit/test_tem_branching.rb", "test/tem_unit/test_tem_crypto_hash.rb", "test/tem_unit/test_tem_crypto_keys.rb", "test/tem_unit/test_tem_crypto_pstore.rb", "test/tem_unit/test_tem_crypto_random.rb", "test/tem_unit/test_tem_emit.rb", "test/tem_unit/test_tem_memory.rb", "test/tem_unit/test_tem_memory_compare.rb", "test/tem_unit/test_tem_output.rb", "test/tem_unit/test_tem_yaml_secpack.rb", "test/test_auto_conf.rb", "test/test_crypto_engine.rb", "test/test_driver.rb", "test/test_exceptions.rb", "tem_ruby.gemspec"]
|
13
|
+
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "bin/tem_bench", "bin/tem_ca", "bin/tem_irb", "bin/tem_proxy", "bin/tem_stat", "bin/tem_upload_fw", "lib/tem/_cert.rb", "lib/tem/admin/emit.rb", "lib/tem/admin/migrate.rb", "lib/tem/apdus/buffers.rb", "lib/tem/apdus/keys.rb", "lib/tem/apdus/lifecycle.rb", "lib/tem/apdus/tag.rb", "lib/tem/auto_conf.rb", "lib/tem/benchmarks/benchmarks.rb", "lib/tem/benchmarks/blank_bound_secpack.rb", "lib/tem/benchmarks/blank_sec.rb", "lib/tem/benchmarks/devchip_decrypt.rb", "lib/tem/benchmarks/post_buffer.rb", "lib/tem/benchmarks/simple_apdu.rb", "lib/tem/benchmarks/vm_perf.rb", "lib/tem/benchmarks/vm_perf_bound.rb", "lib/tem/builders/abi.rb", "lib/tem/builders/assembler.rb", "lib/tem/builders/crypto.rb", "lib/tem/builders/isa.rb", "lib/tem/ca.rb", "lib/tem/definitions/abi.rb", "lib/tem/definitions/assembler.rb", "lib/tem/definitions/isa.rb", "lib/tem/ecert.rb", "lib/tem/firmware/tc.cap", "lib/tem/firmware/uploader.rb", "lib/tem/hive.rb", "lib/tem/keys/asymmetric.rb", "lib/tem/keys/key.rb", "lib/tem/keys/symmetric.rb", "lib/tem/sec_exec_error.rb", "lib/tem/seclosures.rb", "lib/tem/secpack.rb", "lib/tem/tem.rb", "lib/tem/toolkit.rb", "lib/tem_ruby.rb"]
|
14
|
+
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README", "Rakefile", "bin/tem_bench", "bin/tem_ca", "bin/tem_irb", "bin/tem_proxy", "bin/tem_stat", "bin/tem_upload_fw", "dev_ca/ca_cert.cer", "dev_ca/ca_cert.pem", "dev_ca/ca_key.pem", "dev_ca/config.yml", "lib/tem/_cert.rb", "lib/tem/admin/emit.rb", "lib/tem/admin/migrate.rb", "lib/tem/apdus/buffers.rb", "lib/tem/apdus/keys.rb", "lib/tem/apdus/lifecycle.rb", "lib/tem/apdus/tag.rb", "lib/tem/auto_conf.rb", "lib/tem/benchmarks/benchmarks.rb", "lib/tem/benchmarks/blank_bound_secpack.rb", "lib/tem/benchmarks/blank_sec.rb", "lib/tem/benchmarks/devchip_decrypt.rb", "lib/tem/benchmarks/post_buffer.rb", "lib/tem/benchmarks/simple_apdu.rb", "lib/tem/benchmarks/vm_perf.rb", "lib/tem/benchmarks/vm_perf_bound.rb", "lib/tem/builders/abi.rb", "lib/tem/builders/assembler.rb", "lib/tem/builders/crypto.rb", "lib/tem/builders/isa.rb", "lib/tem/ca.rb", "lib/tem/definitions/abi.rb", "lib/tem/definitions/assembler.rb", "lib/tem/definitions/isa.rb", "lib/tem/ecert.rb", "lib/tem/firmware/tc.cap", "lib/tem/firmware/uploader.rb", "lib/tem/hive.rb", "lib/tem/keys/asymmetric.rb", "lib/tem/keys/key.rb", "lib/tem/keys/symmetric.rb", "lib/tem/sec_exec_error.rb", "lib/tem/seclosures.rb", "lib/tem/secpack.rb", "lib/tem/tem.rb", "lib/tem/toolkit.rb", "lib/tem_ruby.rb", "test/_test_cert.rb", "test/builders/test_abi_builder.rb", "test/firmware/test_uploader.rb", "test/tem_test_case.rb", "test/tem_unit/test_tem_alu.rb", "test/tem_unit/test_tem_bound_secpack.rb", "test/tem_unit/test_tem_branching.rb", "test/tem_unit/test_tem_crypto_hash.rb", "test/tem_unit/test_tem_crypto_keys.rb", "test/tem_unit/test_tem_crypto_pstore.rb", "test/tem_unit/test_tem_crypto_random.rb", "test/tem_unit/test_tem_emit.rb", "test/tem_unit/test_tem_memory.rb", "test/tem_unit/test_tem_memory_compare.rb", "test/tem_unit/test_tem_migrate.rb", "test/tem_unit/test_tem_output.rb", "test/tem_unit/test_tem_yaml_secpack.rb", "test/test_auto_conf.rb", "test/test_crypto_engine.rb", "test/test_driver.rb", "test/test_exceptions.rb", "test/test_tag.rb", "tem_ruby.gemspec"]
|
15
15
|
s.homepage = %q{http://tem.rubyforge.org}
|
16
16
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Tem_ruby", "--main", "README"]
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
s.rubyforge_project = %q{tem}
|
19
19
|
s.rubygems_version = %q{1.3.5}
|
20
20
|
s.summary = %q{TEM (Trusted Execution Module) driver, written in and for ruby.}
|
21
|
-
s.test_files = ["test/
|
21
|
+
s.test_files = ["test/builders/test_abi_builder.rb", "test/firmware/test_uploader.rb", "test/tem_unit/test_tem_alu.rb", "test/tem_unit/test_tem_bound_secpack.rb", "test/tem_unit/test_tem_branching.rb", "test/tem_unit/test_tem_crypto_hash.rb", "test/tem_unit/test_tem_crypto_keys.rb", "test/tem_unit/test_tem_crypto_pstore.rb", "test/tem_unit/test_tem_crypto_random.rb", "test/tem_unit/test_tem_emit.rb", "test/tem_unit/test_tem_memory.rb", "test/tem_unit/test_tem_memory_compare.rb", "test/tem_unit/test_tem_migrate.rb", "test/tem_unit/test_tem_output.rb", "test/tem_unit/test_tem_yaml_secpack.rb", "test/test_auto_conf.rb", "test/test_crypto_engine.rb", "test/test_driver.rb", "test/test_exceptions.rb", "test/test_tag.rb"]
|
22
22
|
|
23
23
|
if s.respond_to? :specification_version then
|
24
24
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
@@ -1,35 +1,48 @@
|
|
1
1
|
require 'test/tem_test_case.rb'
|
2
2
|
|
3
3
|
class TemCryptoKeysTest < TemTestCase
|
4
|
+
def i_crypt_len(data_length, key_id, authz)
|
5
|
+
ex_sec = @tem.assemble { |s|
|
6
|
+
s.ldbc :const => 2
|
7
|
+
s.outnew
|
8
|
+
s.ldbc :const => key_id
|
9
|
+
s.authk :auth => :key_auth
|
10
|
+
s.ldwc :const => data_length
|
11
|
+
s.ldkel
|
12
|
+
s.outw
|
13
|
+
s.halt
|
14
|
+
s.label :key_auth
|
15
|
+
s.data :tem_ubyte, authz
|
16
|
+
s.stack 6
|
17
|
+
}
|
18
|
+
Tem::Abi.read_tem_short @tem.execute(ex_sec), 0
|
19
|
+
end
|
20
|
+
|
4
21
|
def i_crypt(data, key_id, authz, mode = :encrypt, direct_io = true,
|
5
22
|
symmetric = false)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
8
|
14
|
-
end
|
15
|
-
else
|
16
|
-
max_output = case mode
|
17
|
-
when :encrypt
|
18
|
-
((data.length + 239) / 240) * 256
|
19
|
-
when :decrypt
|
20
|
-
data.length
|
21
|
-
when :sign
|
22
|
-
256
|
23
|
-
end
|
23
|
+
max_output = case mode
|
24
|
+
when :encrypt
|
25
|
+
(data.length + 239) / 240 * 256
|
26
|
+
when :decrypt
|
27
|
+
data.length
|
28
|
+
when :sign
|
29
|
+
256
|
24
30
|
end
|
25
31
|
|
26
32
|
crypt_opcode =
|
27
33
|
{:encrypt => :kefxb, :decrypt => :kdfxb, :sign => :ksfxb}[mode]
|
28
34
|
ex_sec = @tem.assemble { |s|
|
29
|
-
s.ldwc :const => max_output
|
30
|
-
s.outnew
|
31
35
|
s.ldbc :const => key_id
|
32
36
|
s.authk :auth => :key_auth
|
37
|
+
if mode == :encrypt # Use ldkel to get the max_output value.
|
38
|
+
s.dupn :n => 1
|
39
|
+
s.ldwc :const => data.length
|
40
|
+
s.ldkel
|
41
|
+
else
|
42
|
+
s.ldwc :const => max_output
|
43
|
+
end
|
44
|
+
s.outnew
|
45
|
+
|
33
46
|
s.send crypt_opcode, :from => :data, :size => data.length,
|
34
47
|
:to => (direct_io ? 0xFFFF : :outdata)
|
35
48
|
s.outvlb :from => :outdata unless direct_io
|
@@ -45,7 +58,7 @@ class TemCryptoKeysTest < TemTestCase
|
|
45
58
|
end
|
46
59
|
s.stack 5
|
47
60
|
}
|
48
|
-
|
61
|
+
@tem.execute ex_sec
|
49
62
|
end
|
50
63
|
|
51
64
|
def i_verify(data, signature, key_id, authz)
|
@@ -66,12 +79,17 @@ class TemCryptoKeysTest < TemTestCase
|
|
66
79
|
s.data :tem_ubyte, signature
|
67
80
|
s.stack 5
|
68
81
|
}
|
69
|
-
|
82
|
+
@tem.execute(sign_sec)[0] == 1
|
70
83
|
end
|
71
84
|
|
72
85
|
def i_test_crypto_pks_ops(pubk_id, privk_id, pubk, privk, authz)
|
73
86
|
garbage = (0...569).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
|
74
87
|
|
88
|
+
# Obtaining the length of encrypted data.
|
89
|
+
crypt_length = i_crypt_len garbage.length, pubk_id, authz
|
90
|
+
assert_equal((garbage.length + 239) / 240 * 256, crypt_length,
|
91
|
+
'Incorrect result from ldkel')
|
92
|
+
|
75
93
|
# SEC/priv-sign + CPU/pub-verify, direct IO.
|
76
94
|
signed_garbage = i_crypt garbage, privk_id, authz, :sign, true
|
77
95
|
assert privk.verify(garbage, signed_garbage),
|
@@ -134,6 +152,11 @@ class TemCryptoKeysTest < TemTestCase
|
|
134
152
|
def i_test_crypto_sks_ops(skey_id, skey, authz)
|
135
153
|
garbage = (0...569).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
|
136
154
|
|
155
|
+
# Obtaining the length of encrypted data.
|
156
|
+
crypt_length = i_crypt_len garbage.length, skey_id, authz
|
157
|
+
assert_equal((garbage.length + 8) / 8 * 8, crypt_length,
|
158
|
+
'Incorrect result from ldkel')
|
159
|
+
|
137
160
|
# SEC/sign + CPU/verify, direct IO.
|
138
161
|
signed_garbage = i_crypt garbage, skey_id, authz, :sign, true, true
|
139
162
|
assert skey.verify(garbage, signed_garbage),
|
@@ -2,12 +2,12 @@ require 'test/tem_test_case.rb'
|
|
2
2
|
|
3
3
|
class TemCryptoPstoreTest < TemTestCase
|
4
4
|
def test_crypto_pstore
|
5
|
-
addr1 = (0...(
|
5
|
+
addr1 = (0...(Tem::Abi.tem_ps_addr_length)).map { |x| (61 * x * x + 62 * x + 10) % 256 }
|
6
6
|
addr2 = addr1.dup; addr2[addr2.length - 1] += 1
|
7
|
-
random_value = (0...(
|
7
|
+
random_value = (0...(Tem::Abi.tem_ps_value_length)).map { |x| (69 * x * x + 62 * x + 10) % 256 }
|
8
8
|
|
9
9
|
sec = @tem.assemble { |s|
|
10
|
-
s.ldwc
|
10
|
+
s.ldwc 2 * @tem.tem_ushort_length + @tem.tem_ps_value_length
|
11
11
|
s.outnew
|
12
12
|
|
13
13
|
# check that the location is blank
|
@@ -23,10 +23,39 @@ class TemCryptoPstoreTest < TemTestCase
|
|
23
23
|
# re-read (should get what was written)
|
24
24
|
s.ldwc :pstore_addr
|
25
25
|
s.ldwc :s_value2
|
26
|
-
s.psrdvb
|
26
|
+
s.psrdvb
|
27
27
|
s.ldwc :s_value2
|
28
28
|
s.outvb
|
29
|
+
s.halt
|
30
|
+
|
31
|
+
s.label :pstore_addr
|
32
|
+
s.data :tem_ubyte, addr1
|
33
|
+
s.label :s_value
|
34
|
+
s.data :tem_ubyte, random_value
|
35
|
+
s.label :s_value2
|
36
|
+
s.zeros :tem_ps_value
|
37
|
+
s.stack 8
|
38
|
+
}
|
39
|
+
expected = @tem.to_tem_ushort(0) + @tem.to_tem_ushort(1) + random_value
|
40
|
+
result = @tem.execute sec
|
41
|
+
assert_equal expected, result,
|
42
|
+
"Persistent store locations aren\'t working well"
|
29
43
|
|
44
|
+
sec = @tem.assemble { |s|
|
45
|
+
s.ldwc 2 * @tem.tem_ushort_length + @tem.tem_ps_value_length
|
46
|
+
s.outnew
|
47
|
+
|
48
|
+
# check that the location isn't blank anymore
|
49
|
+
s.pshkfxb :addr => :pstore_addr
|
50
|
+
s.outw
|
51
|
+
|
52
|
+
# re-read (should get what was written)
|
53
|
+
s.ldwc :pstore_addr
|
54
|
+
s.ldwc :s_value2
|
55
|
+
s.psrdvb
|
56
|
+
s.ldwc :s_value2
|
57
|
+
s.outvb
|
58
|
+
|
30
59
|
# drop the location
|
31
60
|
s.ldwc :pstore_addr
|
32
61
|
s.dupn :n => 1
|
@@ -45,9 +74,9 @@ class TemCryptoPstoreTest < TemTestCase
|
|
45
74
|
s.zeros :tem_ps_value
|
46
75
|
s.stack 8
|
47
76
|
}
|
48
|
-
expected = @tem.to_tem_ushort(
|
49
|
-
@tem.to_tem_ushort(0)
|
77
|
+
expected = @tem.to_tem_ushort(1) + random_value + @tem.to_tem_ushort(0)
|
50
78
|
result = @tem.execute sec
|
51
|
-
assert_equal expected, result,
|
79
|
+
assert_equal expected, result,
|
80
|
+
"Persistent store data didn't survive across SECpack execution"
|
52
81
|
end
|
53
82
|
end
|
@@ -2,22 +2,21 @@ require 'test/tem_test_case.rb'
|
|
2
2
|
|
3
3
|
class TemEmitTest < TemTestCase
|
4
4
|
def test_emit
|
5
|
-
#
|
6
|
-
|
7
|
-
assert
|
5
|
+
# Try to emit the TEM.
|
6
|
+
privek_auth = @tem.emit
|
7
|
+
assert privek_auth != nil, 'TEM emitting failed'
|
8
8
|
|
9
|
-
#
|
10
|
-
privek = @tem.tk_read_key 0,
|
11
|
-
assert((not privek.is_public?),
|
9
|
+
# Verify that the private key is good and the authorization matches.
|
10
|
+
privek = @tem.tk_read_key 0, privek_auth
|
11
|
+
assert((not privek.is_public?),
|
12
|
+
'TEM emission failed to produce a proper PrivEK')
|
12
13
|
|
13
|
-
#
|
14
|
+
# Verify that the public key can be read from the ECert.
|
14
15
|
pubek = @tem.pubek
|
15
16
|
assert pubek.is_public?, 'TEM emission failed to produce a proper PubEK'
|
16
17
|
|
17
|
-
#
|
18
|
+
# Verify the PrivEK against the ECert.
|
18
19
|
ecert = @tem.endorsement_cert
|
19
20
|
ecert.verify privek.ssl_key
|
20
|
-
|
21
|
-
@tem.tk_delete_key 0, er[:privek_auth]
|
22
|
-
end
|
21
|
+
end
|
23
22
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test/tem_test_case.rb'
|
2
|
+
|
3
|
+
class TemMigrateTest < TemTestCase
|
4
|
+
def _migrate_test_secret
|
5
|
+
[0x31, 0x41, 0x59, 0x65, 0x35]
|
6
|
+
end
|
7
|
+
|
8
|
+
def _migrate_test_seclosure
|
9
|
+
Tem::Assembler.assemble { |s|
|
10
|
+
s.label :secret
|
11
|
+
s.ldbc :const => _migrate_test_secret.length
|
12
|
+
s.dupn :n => 1
|
13
|
+
s.outnew
|
14
|
+
s.outvlb :from => :dump_data
|
15
|
+
s.halt
|
16
|
+
s.label :dump_data
|
17
|
+
s.data :tem_ubyte, _migrate_test_secret
|
18
|
+
s.label :plain
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_migrate
|
23
|
+
# Emit the TEM, bind the SECpack, and test it.
|
24
|
+
privek_auth = @tem.emit
|
25
|
+
sec = _migrate_test_seclosure
|
26
|
+
sec.bind @tem.pubek, :secret, :plain
|
27
|
+
assert_equal _migrate_test_secret, @tem.execute(sec),
|
28
|
+
'Migration test SECpack incorrect'
|
29
|
+
|
30
|
+
# The migration target key pair.
|
31
|
+
ekey = OpenSSL::PKey::RSA.generate(2048, 65537)
|
32
|
+
privk = Tem::Key.new_from_ssl_key ekey
|
33
|
+
pubk = Tem::Key.new_from_ssl_key ekey.public_key
|
34
|
+
ecert2 = Tem::CA.new_ecert pubk.ssl_key
|
35
|
+
migrated = @tem.migrate sec, ecert2
|
36
|
+
|
37
|
+
authz = [0] * 20
|
38
|
+
privk_id = @tem.tk_post_key privk, authz
|
39
|
+
assert_equal _migrate_test_secret, @tem.execute(migrated, privk_id),
|
40
|
+
'Migrated SECpack executed incorrectly'
|
41
|
+
@tem.tk_delete_key privk_id, authz
|
42
|
+
end
|
43
|
+
end
|
data/test/test_driver.rb
CHANGED
@@ -49,16 +49,5 @@ class DriverTest < TemTestCase
|
|
49
49
|
end
|
50
50
|
|
51
51
|
b_ids.each { |bid| @tem.release_buffer(bid) }
|
52
|
-
end
|
53
|
-
|
54
|
-
def test_tag
|
55
|
-
garbage = (1...569).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
|
56
|
-
|
57
|
-
assert_raise Smartcard::Iso::ApduError, 'tag returned before being set' do
|
58
|
-
@tem.get_tag
|
59
|
-
end
|
60
|
-
|
61
|
-
@tem.set_tag garbage
|
62
|
-
assert_equal garbage, @tem.get_tag, 'error in posted tag data'
|
63
|
-
end
|
52
|
+
end
|
64
53
|
end
|
data/test/test_tag.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test/tem_test_case.rb'
|
2
|
+
|
3
|
+
|
4
|
+
class DriverTest < TemTestCase
|
5
|
+
def test_tag_reading_before_writing
|
6
|
+
assert_raise Smartcard::Iso::ApduError,
|
7
|
+
'Tag length returned before being set' do
|
8
|
+
@tem.get_raw_tag_length
|
9
|
+
end
|
10
|
+
|
11
|
+
assert_raise Smartcard::Iso::ApduError,
|
12
|
+
'Tag data returned before being set' do
|
13
|
+
@tem.get_raw_tag_data 0, 1
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_raw_tag_io
|
18
|
+
garbage = (1...569).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
|
19
|
+
|
20
|
+
@tem.set_raw_tag_data garbage
|
21
|
+
assert_equal garbage.length, @tem.get_raw_tag_length,
|
22
|
+
'Error in raw tag length'
|
23
|
+
assert_equal garbage[19, 400], @tem.get_raw_tag_data(19, 400),
|
24
|
+
'Error in raw tag data partial read'
|
25
|
+
assert_equal garbage, @tem.get_raw_tag_data(0, garbage.length),
|
26
|
+
'Error in raw tag data full read'
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_structured_tag
|
30
|
+
g1 = (1...569).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
|
31
|
+
g2 = (570...1032).map { |i| (i * i * 217 + i * 661 + 393) % 256 }
|
32
|
+
tag_data = { 0x01 => g1, 0x11 => g2 }
|
33
|
+
|
34
|
+
encoded = Tem::Apdus::Tag.encode_tag tag_data
|
35
|
+
assert_equal tag_data, Tem::Apdus::Tag.decode_tag(encoded),
|
36
|
+
'Inconsistency in TLV encoding / decoding'
|
37
|
+
|
38
|
+
@tem.set_tag tag_data
|
39
|
+
@tem.clear_icache
|
40
|
+
assert_equal tag_data, @tem.tag
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tem_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Costan
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-18 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -64,6 +64,8 @@ extra_rdoc_files:
|
|
64
64
|
- bin/tem_stat
|
65
65
|
- bin/tem_upload_fw
|
66
66
|
- lib/tem/_cert.rb
|
67
|
+
- lib/tem/admin/emit.rb
|
68
|
+
- lib/tem/admin/migrate.rb
|
67
69
|
- lib/tem/apdus/buffers.rb
|
68
70
|
- lib/tem/apdus/keys.rb
|
69
71
|
- lib/tem/apdus/lifecycle.rb
|
@@ -115,6 +117,8 @@ files:
|
|
115
117
|
- dev_ca/ca_key.pem
|
116
118
|
- dev_ca/config.yml
|
117
119
|
- lib/tem/_cert.rb
|
120
|
+
- lib/tem/admin/emit.rb
|
121
|
+
- lib/tem/admin/migrate.rb
|
118
122
|
- lib/tem/apdus/buffers.rb
|
119
123
|
- lib/tem/apdus/keys.rb
|
120
124
|
- lib/tem/apdus/lifecycle.rb
|
@@ -163,12 +167,14 @@ files:
|
|
163
167
|
- test/tem_unit/test_tem_emit.rb
|
164
168
|
- test/tem_unit/test_tem_memory.rb
|
165
169
|
- test/tem_unit/test_tem_memory_compare.rb
|
170
|
+
- test/tem_unit/test_tem_migrate.rb
|
166
171
|
- test/tem_unit/test_tem_output.rb
|
167
172
|
- test/tem_unit/test_tem_yaml_secpack.rb
|
168
173
|
- test/test_auto_conf.rb
|
169
174
|
- test/test_crypto_engine.rb
|
170
175
|
- test/test_driver.rb
|
171
176
|
- test/test_exceptions.rb
|
177
|
+
- test/test_tag.rb
|
172
178
|
- tem_ruby.gemspec
|
173
179
|
has_rdoc: true
|
174
180
|
homepage: http://tem.rubyforge.org
|
@@ -204,21 +210,23 @@ signing_key:
|
|
204
210
|
specification_version: 3
|
205
211
|
summary: TEM (Trusted Execution Module) driver, written in and for ruby.
|
206
212
|
test_files:
|
207
|
-
- test/test_driver.rb
|
208
|
-
- test/firmware/test_uploader.rb
|
209
|
-
- test/test_auto_conf.rb
|
210
213
|
- test/builders/test_abi_builder.rb
|
211
|
-
- test/
|
212
|
-
- test/tem_unit/test_tem_crypto_keys.rb
|
213
|
-
- test/tem_unit/test_tem_yaml_secpack.rb
|
214
|
+
- test/firmware/test_uploader.rb
|
214
215
|
- test/tem_unit/test_tem_alu.rb
|
215
|
-
- test/tem_unit/test_tem_crypto_hash.rb
|
216
216
|
- test/tem_unit/test_tem_bound_secpack.rb
|
217
|
-
- test/tem_unit/test_tem_memory_compare.rb
|
218
|
-
- test/tem_unit/test_tem_output.rb
|
219
|
-
- test/tem_unit/test_tem_crypto_random.rb
|
220
|
-
- test/tem_unit/test_tem_memory.rb
|
221
217
|
- test/tem_unit/test_tem_branching.rb
|
218
|
+
- test/tem_unit/test_tem_crypto_hash.rb
|
219
|
+
- test/tem_unit/test_tem_crypto_keys.rb
|
222
220
|
- test/tem_unit/test_tem_crypto_pstore.rb
|
223
|
-
- test/
|
221
|
+
- test/tem_unit/test_tem_crypto_random.rb
|
222
|
+
- test/tem_unit/test_tem_emit.rb
|
223
|
+
- test/tem_unit/test_tem_memory.rb
|
224
|
+
- test/tem_unit/test_tem_memory_compare.rb
|
225
|
+
- test/tem_unit/test_tem_migrate.rb
|
226
|
+
- test/tem_unit/test_tem_output.rb
|
227
|
+
- test/tem_unit/test_tem_yaml_secpack.rb
|
228
|
+
- test/test_auto_conf.rb
|
224
229
|
- test/test_crypto_engine.rb
|
230
|
+
- test/test_driver.rb
|
231
|
+
- test/test_exceptions.rb
|
232
|
+
- test/test_tag.rb
|