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