tem_ruby 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -1,3 +1,5 @@
1
+ v0.10.0. New transport code, allowing for multiple readers and TEM proxying.
2
+
1
3
  v0.9.2. Changed exec-SECpack calling sequence for fw 1.9.1(fire, the released version).
2
4
 
3
5
  v0.9.1. Cleaner names for the pstore data types and opcode arguments. "Bound" instead of "sealed" SECpack.
data/Manifest CHANGED
@@ -1,45 +1,56 @@
1
- bin/tem_stat
1
+ bin/tem_bench
2
2
  bin/tem_ca
3
3
  bin/tem_irb
4
- bin/tem_bench
5
- Manifest
6
- LICENSE
7
- test/test_driver.rb
8
- test/test_tem.rb
9
- test/test_exceptions.rb
10
- test/_test_cert.rb
11
- timings/vm_perf.rb
12
- timings/devchip_decrypt.rb
13
- timings/simple_apdu.rb
14
- timings/post_buffer.rb
15
- timings/blank_bound_secpack.rb
16
- timings/vm_perf_bound.rb
17
- timings/timings.rb
18
- timings/blank_sec.rb
19
- lib/scard/java_card.rb
20
- lib/scard/jcop_remote_terminal.rb
21
- lib/scard/pcsc_terminal.rb
22
- lib/tem_ruby.rb
23
- lib/tem/tag.rb
24
- lib/tem/keys.rb
25
- lib/tem/sec_opcodes.rb
4
+ bin/tem_proxy
5
+ bin/tem_stat
6
+ CHANGELOG
7
+ dev_ca/ca_cert.cer
8
+ dev_ca/ca_cert.pem
9
+ dev_ca/ca_key.pem
10
+ dev_ca/config.yml
26
11
  lib/tem/_cert.rb
27
- lib/tem/buffers.rb
28
- lib/tem/toolkit.rb
29
- lib/tem/tem.rb
30
12
  lib/tem/abi.rb
31
- lib/tem/crypto_abi.rb
13
+ lib/tem/auto_conf.rb
14
+ lib/tem/buffers.rb
32
15
  lib/tem/ca.rb
33
- lib/tem/secpack.rb
34
- lib/tem/sec_exec_error.rb
35
- lib/tem/sec_assembler.rb
36
- lib/tem/lifecycle.rb
16
+ lib/tem/crypto_abi.rb
37
17
  lib/tem/ecert.rb
38
18
  lib/tem/hive.rb
19
+ lib/tem/keys.rb
20
+ lib/tem/lifecycle.rb
21
+ lib/tem/sec_assembler.rb
22
+ lib/tem/sec_exec_error.rb
23
+ lib/tem/sec_opcodes.rb
39
24
  lib/tem/seclosures.rb
25
+ lib/tem/secpack.rb
26
+ lib/tem/tag.rb
27
+ lib/tem/tem.rb
28
+ lib/tem/toolkit.rb
29
+ lib/tem/transport/auto_configurator.rb
30
+ lib/tem/transport/java_card_mixin.rb
31
+ lib/tem/transport/jcop_remote_protocol.rb
32
+ lib/tem/transport/jcop_remote_server.rb
33
+ lib/tem/transport/jcop_remote_transport.rb
34
+ lib/tem/transport/pcsc_transport.rb
35
+ lib/tem/transport/transport.rb
36
+ lib/tem_ruby.rb
37
+ LICENSE
38
+ Manifest
39
+ Rakefile
40
40
  README
41
- CHANGELOG
42
- dev_ca/ca_cert.cer
43
- dev_ca/ca_cert.pem
44
- dev_ca/ca_key.pem
45
- dev_ca/config.yml
41
+ test/_test_cert.rb
42
+ test/tem_test_case.rb
43
+ test/test_driver.rb
44
+ test/test_exceptions.rb
45
+ test/test_tem.rb
46
+ test/transport/test_auto_configurator.rb
47
+ test/transport/test_java_card_mixin.rb
48
+ test/transport/test_jcop_remote.rb
49
+ timings/blank_bound_secpack.rb
50
+ timings/blank_sec.rb
51
+ timings/devchip_decrypt.rb
52
+ timings/post_buffer.rb
53
+ timings/simple_apdu.rb
54
+ timings/timings.rb
55
+ timings/vm_perf.rb
56
+ timings/vm_perf_bound.rb
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ gem 'echoe'
3
+ require 'echoe'
4
+
5
+ Echoe.new('tem_ruby') do |p|
6
+ p.project = 'tem' # rubyforge project
7
+ p.docs_host = "costan@rubyforge.org:/var/www/gforge-projects/tem/rdoc/"
8
+
9
+ p.author = 'Victor Costan'
10
+ p.email = 'victor@costan.us'
11
+ p.summary = 'TEM (Trusted Execution Module) driver, written in and for ruby.'
12
+ p.url = 'http://tem.rubyforge.org'
13
+ p.dependencies = ['smartcard >=0.3.0']
14
+
15
+ p.need_tar_gz = !Platform.windows?
16
+ p.need_zip = !Platform.windows?
17
+ p.rdoc_pattern = /^(lib|bin|tasks|ext)|^BUILD|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
18
+ end
19
+
20
+ if $0 == __FILE__
21
+ Rake.application = Rake::Application.new
22
+ Rake.application.run
23
+ end
data/bin/tem_bench CHANGED
File without changes
data/bin/tem_ca CHANGED
File without changes
data/bin/tem_irb CHANGED
@@ -6,13 +6,6 @@ require 'tem_ruby'
6
6
 
7
7
  require 'irb'
8
8
 
9
- $terminal = Tem::SCard::JCOPRemoteTerminal.new
10
- unless $terminal.connect
11
- $terminal.disconnect
12
- $terminal = Tem::SCard::PCSCTerminal.new
13
- $terminal.connect
14
- end
15
- $javacard = Tem::SCard::JavaCard.new($terminal)
16
- $tem = Tem::Session.new($javacard)
9
+ Tem.auto_conf
17
10
 
18
11
  IRB.start __FILE__
data/bin/tem_proxy ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # TEM transport-level proxy.
4
+ # Serves a TCP connection
5
+
6
+ require 'logger'
7
+
8
+ require 'rubygems'
9
+ require 'tem_ruby'
10
+
11
+ # JCOP remote serving logic implementing a proxy to another transport.
12
+ class ServingLogic
13
+ include Tem::Transport::JcopRemoteServingStubs
14
+ def initialize(serving_transport, logging = false)
15
+ @serving = serving_transport
16
+ @logger = Logger.new STDERR
17
+ @logger.level = logging ? Logger::DEBUG : Logger::FATAL
18
+ @connected = true
19
+ end
20
+ def connection_start
21
+ @logger.info "Connection start"
22
+ unless @connected
23
+ @serving.connect
24
+ @connected = true
25
+ end
26
+ end
27
+ def connection_end
28
+ @logger.info "Connection end"
29
+ @serving.disconnect if @connected
30
+ @connected = false
31
+ end
32
+ def exchange_apdu(apdu)
33
+ @logger.info "APDU request: #{apdu.map { |n| '%02x' % n }.join(' ')}"
34
+ response = @serving.exchange_apdu apdu
35
+ @logger.info "APDU response: #{response.map { |n| '%02x' % n }.join(' ')}"
36
+ response
37
+ end
38
+ end
39
+
40
+ # Indefinitely runs a JCOP remove serving loop that proxies to another TEM
41
+ # transport.
42
+ #
43
+ # The TEM transport is automatically configured based on environment information
44
+ # and defaults.
45
+ #
46
+ def serve(options)
47
+ @logger = Logger.new STDERR
48
+ @logger.level = options[:logging] ? Logger::DEBUG : Logger::FATAL
49
+
50
+ serving_transport = Tem::Transport.auto_transport
51
+ @logger.info "Proxying to #{serving_transport.inspect}\n"
52
+ @logger.info "Serving with #{options.inspect}\n"
53
+ serving_logic = ServingLogic.new serving_transport, options[:logging]
54
+ Tem::Transport::JcopRemoteServer.new(options, serving_logic).run
55
+ end
56
+
57
+ # Parses the commmand-line arguments into an options hash suitable for #serve.
58
+ def parse_args
59
+ { :ip => ARGV[1] || '0.0.0.0', :port => (ARGV[0] || '9000').to_i,
60
+ :logging => !(ENV['DEBUG'] &&
61
+ ['0', 'no', 'false'].include?(ENV['DEBUG'].downcase)) }
62
+ end
63
+
64
+ options = parse_args
65
+ serve options
data/bin/tem_stat CHANGED
@@ -5,35 +5,31 @@ require 'rubygems'
5
5
  require 'tem_ruby'
6
6
  require 'pp'
7
7
 
8
- $terminal = Tem::SCard::JCOPRemoteTerminal.new
9
- unless $terminal.connect
10
- $terminal.disconnect
11
- $terminal = Tem::SCard::PCSCTerminal.new
12
- $terminal.connect
13
- end
14
- $javacard = Tem::SCard::JavaCard.new($terminal)
15
- $tem = Tem::Session.new($javacard)
8
+ Tem.auto_conf
16
9
 
17
- print "Connected to TEM using #{$terminal.to_s}\n"
10
+ print "Connected to TEM using #{$tem.transport.inspect}\n"
18
11
  begin
19
12
  fw_ver = $tem.tk_firmware_ver
20
13
  print "TEM firmware version: #{fw_ver[:major]}.#{fw_ver[:minor]}\n"
21
- rescue
14
+ rescue Exception => e
22
15
  print "Could not read TEM firmware version. Is the TEM emitted?\n"
16
+ print "#{e.class.name}: #{e}\n#{e.backtrace.join("\n")}\n"
23
17
  end
24
18
 
25
19
  begin
26
20
  b_stat = $tem.stat_buffers
27
21
  print "TEM memory stat:\n"
28
22
  pp b_stat
29
- rescue
23
+ rescue Exception => e
30
24
  print "Could not retrieve TEM memory stat. Is the TEM activated?\n"
25
+ print "#{e.class.name}: #{e}\n#{e.backtrace.join("\n")}\n"
31
26
  end
32
27
 
33
28
  begin
34
29
  k_stat = $tem.stat_keys
35
30
  print "TEM crypto stat:\n"
36
31
  pp k_stat
37
- rescue
32
+ rescue Exception => e
38
33
  print "Could not retrieve TEM crypto stat. Is the TEM activated?\n"
34
+ print "#{e.class.name}: #{e}\n#{e.backtrace.join("\n")}\n"
39
35
  end
data/dev_ca/config.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  ---
2
+ # the development CA is valid for 10 years
2
3
  :ca_validity_days: 3652
3
4
  :issuer:
4
5
  CN: Trusted Execution Module Development CA
@@ -7,6 +8,7 @@
7
8
  C: US
8
9
  O: Massachusetts Insitute of Technology
9
10
  OU: Computer Science and Artificial Intelligence Laboratory
11
+ # a TEM is valid for two days
10
12
  :ecert_validity_days: 730
11
13
  :subject:
12
14
  CN: Trusted Execution Module DevChip
@@ -0,0 +1,25 @@
1
+ module Tem
2
+ # Automatically configures a TEM.
3
+ #
4
+ # In case of success, the $tem global variable is set to a Tem::Session that
5
+ # can be used to talk to some TEM. An exception will be raised if the session
6
+ # creation fails.
7
+ #
8
+ # It is safe to call auto_conf multiple times. A single session will be open.
9
+ def self.auto_conf
10
+ return $tem if $tem
11
+ $tem = auto_tem
12
+ end
13
+
14
+ # Creates a new session to a TEM, using an automatically-configured transport.
15
+ # :call-seq:
16
+ # Tem.auto_tem -> Tem::Session
17
+ #
18
+ # In case of success, returns a Tem::Session that can be used to talk to some
19
+ # TEM. An exception will be raised if the session creation fails.
20
+ def self.auto_tem
21
+ transport = Tem::Transport.auto_transport
22
+ raise 'No suitable TEM was found' unless transport
23
+ Tem::Session.new transport
24
+ end
25
+ end
data/lib/tem/buffers.rb CHANGED
@@ -1,77 +1,64 @@
1
1
  module Tem::Buffers
2
2
  def alloc_buffer(length)
3
- apdu = [0x00, 0x20, to_tem_short(length), 0x00].flatten
4
- response = issue_apdu apdu
5
- tem_error(response) if failure_code(response)
3
+ response = @transport.applet_apdu! :ins => 0x20,
4
+ :p12 => to_tem_short(length)
6
5
  return read_tem_byte(response, 0)
7
6
  end
8
7
 
9
8
  def release_buffer(buffer_id)
10
- apdu = [0x00, 0x21, to_tem_byte(buffer_id), 0x00, 0x00].flatten
11
- response = issue_apdu apdu
12
- tem_error(response) if failure_code(response)
13
- return true
9
+ @transport.applet_apdu! :ins => 0x21, :p1 => buffer_id
14
10
  end
15
11
 
16
12
  def flush_buffers
17
- apdu = [0x00, 0x26, 0x00, 0x00, 0x00].flatten
18
- response = issue_apdu apdu
19
- tem_error(response) if failure_code(response)
20
- return true
13
+ @transport.applet_apdu! :ins => 0x26
21
14
  end
22
15
 
23
16
  def get_buffer_length(buffer_id)
24
- apdu = [0x00, 0x22, to_tem_byte(buffer_id), 0x00, 0x00].flatten
25
- response = issue_apdu apdu
26
- tem_error(response) if failure_code(response)
17
+ response = @transport.applet_apdu! :ins => 0x22, :p1 => buffer_id
27
18
  return read_tem_short(response, 0)
28
19
  end
29
20
 
30
21
  def read_buffer(buffer_id)
31
- @buffer_chunk_size = guess_buffer_chunk_size unless defined? @buffer_chunk_size
22
+ guess_buffer_chunk_size
32
23
 
33
24
  buffer = []
34
25
  chunk_id = 0
35
26
  while true do
36
- apdu = [0x00, 0x23, to_tem_byte(buffer_id), to_tem_byte(chunk_id), 0x00].flatten
37
- response = issue_apdu apdu
38
- tem_error(response) if failure_code(response)
39
- buffer += response[0...(response.length - 2)]
40
- break if response.length != @buffer_chunk_size + 2
27
+ response = @transport.applet_apdu! :ins => 0x23, :p1 => buffer_id,
28
+ :p2 => chunk_id
29
+ buffer += response
30
+ break if response.length != @buffer_chunk_size
41
31
  chunk_id += 1
42
32
  end
43
33
  return buffer
44
34
  end
45
35
 
46
36
  def write_buffer(buffer_id, data)
47
- @buffer_chunk_size = guess_buffer_chunk_size unless defined? @buffer_chunk_size
37
+ guess_buffer_chunk_size
48
38
 
49
39
  chunk_id, offset = 0, 0
50
40
  while offset < data.length do
51
41
  write_size = (data.length - offset < @buffer_chunk_size) ?
52
42
  data.length - offset : @buffer_chunk_size
53
- apdu = [0x00, 0x24, to_tem_byte(buffer_id), to_tem_byte(chunk_id), to_tem_ubyte(write_size),
54
- data.values_at(offset...(offset+write_size))].flatten
55
- response = issue_apdu apdu
56
- tem_error(response) if failure_code(response)
57
-
43
+ @transport.applet_apdu! :ins => 0x24, :p1 => buffer_id, :p2 => chunk_id,
44
+ :data => data[offset, write_size]
58
45
  chunk_id += 1
59
46
  offset += write_size
60
47
  end
61
48
  end
62
49
 
63
50
  def guess_buffer_chunk_size
64
- apdu = [0x00, 0x25, 0x00, 0x00, 0x00].flatten
65
- response = issue_apdu apdu
66
- tem_error(response) if failure_code(response)
51
+ @buffer_chunk_size ||= guess_buffer_chunk_size!
52
+ end
53
+
54
+ def guess_buffer_chunk_size!
55
+ response = @transport.applet_apdu! :ins => 0x25
67
56
  return read_tem_short(response, 0)
68
57
  end
69
58
 
70
59
  def stat_buffers
71
- apdu = [0x00, 0x27, 0x00, 0x00, 0x00].flatten
72
- response = issue_apdu apdu
73
- tem_error(response) if failure_code(response)
74
- response = reply_data(response)
60
+ response = @transport.applet_apdu! :ins => 0x27
61
+
75
62
  memory_types = [:persistent, :clear_on_reset, :clear_on_deselect]
76
63
  stat = {:free => {}, :buffers => []}
77
64
  memory_types.each_with_index { |mt, i| stat[:free][mt] = read_tem_short(response, i * 2) }
@@ -91,7 +78,7 @@ module Tem::Buffers
91
78
  end
92
79
 
93
80
  def post_buffer(data)
94
- buffer_id = alloc_buffer(data.length)
81
+ buffer_id = alloc_buffer data.length
95
82
  write_buffer buffer_id, data
96
83
  return buffer_id
97
84
  end
@@ -5,12 +5,16 @@ require 'yaml'
5
5
  module Tem::CryptoAbi
6
6
  include Tem::Abi
7
7
 
8
- # contains the methods
8
+ # The methods that will be mixed into the TEM module
9
9
  module MixedMethods
10
+ # Reads a TEM-encoded big number.
10
11
  def read_tem_bignum(buffer, offset, length)
11
- return buffer[offset...(offset+length)].inject(0) { |num, digit| num = (num << 8) | digit }
12
+ return buffer[offset...(offset+length)].inject(0) do |num, digit|
13
+ num = (num << 8) | digit
14
+ end
12
15
  end
13
-
16
+
17
+ # Returns the TEM encoding for a big number.
14
18
  def to_tem_bignum(n)
15
19
  if n.kind_of? OpenSSL::BN
16
20
  len = n.num_bytes
@@ -33,19 +37,30 @@ module Tem::CryptoAbi
33
37
  return q.reverse
34
38
  end
35
39
  end
36
-
40
+
37
41
  def load_tem_key_material(key, syms, buffer, offset)
38
- lengths = (0...syms.length).map { |i| read_tem_short(buffer, offset + i * 2)}
42
+ lengths = (0...syms.length).map do |i|
43
+ read_tem_short buffer, offset + i * 2
44
+ end
39
45
  offsets = [offset + syms.length * 2]
40
- 1.upto(syms.length - 1) { |i| offsets[i] = offsets[i - 1] + lengths[i - 1] }
41
- 0.upto(syms.length - 1) do |i|
42
- key.send((syms[i].to_s + '=').to_sym, read_tem_bignum(buffer, offsets[i], lengths[i]))
43
- end
46
+ syms.each_index { |i| offsets[i + 1] = offsets[i] + lengths[i] }
47
+ syms.each_index do |i|
48
+ key.send((syms[i].to_s + '=').to_sym,
49
+ read_tem_bignum(buffer, offsets[i], lengths[i]))
50
+ end
44
51
  end
45
-
52
+
53
+ # The length of a TEM symmetric key.
54
+ def tem_symmetric_key_length
55
+ 16 # 128 bits
56
+ end
57
+
46
58
  def read_tem_key(buffer, offset)
47
59
  key_type = read_tem_ubyte buffer, offset
48
- if key_type == 0xAA || key_type == 0x55
60
+ case key_type
61
+ when 0x99
62
+ key = buffer[offset, tem_symmetric_key_length]
63
+ when 0xAA, 0x55
49
64
  key = OpenSSL::PKey::RSA.new
50
65
  syms = (key_type == 0xAA) ? [:e, :n] : [:p, :q, :dmp1, :dmq1, :iqmp]
51
66
  load_tem_key_material key, syms, buffer, offset + 1
@@ -61,10 +76,10 @@ module Tem::CryptoAbi
61
76
  key.e = (emp1 < emq1) ? emp1 : emq1
62
77
  key.d = key.e.mod_inverse(p1q1)
63
78
  end
64
- return new_key_from_ssl(key, (key_type == 0xAA))
65
79
  else
66
80
  raise "Invalid key type #{'%02x' % key_type}"
67
81
  end
82
+ return new_key_from_ssl(key, (key_type == 0xAA))
68
83
  end
69
84
 
70
85
  def to_tem_key(ssl_key, type)
@@ -78,18 +93,19 @@ module Tem::CryptoAbi
78
93
  end
79
94
  end
80
95
 
96
+ # Creates a new TEM key wrapper from a SSL key
81
97
  def new_key_from_ssl(ssl_key, is_public)
82
- AsymmetricKey.new(ssl_key, is_public, :pkcs1)
98
+ if ssl_key.kind_of? OpenSSL::PKey::RSA
99
+ AsymmetricKey.new ssl_key, is_public, :pkcs1
100
+ else
101
+ SymmetricKey.new ssl_key
102
+ end
83
103
  end
84
104
 
105
+ # Compute a cryptographic hash in the same way that the TEM does.
85
106
  def hash_for_tem(data)
86
- if data.kind_of? String
87
- data_string = data
88
- else
89
- data_string = data.pack('C*')
90
- end
91
- digest_string = Digest::SHA1.digest(data_string)
92
- return digest_string.unpack('C*')
107
+ data = data.pack 'C*' unless data.kind_of? String
108
+ Digest::SHA1.digest(data).unpack 'C*'
93
109
  end
94
110
  end
95
111
 
@@ -104,13 +120,19 @@ module Tem::CryptoAbi
104
120
  end
105
121
 
106
122
  def self.load_ssl(ssl_key)
107
- return {:pubkey => AsymmetricKey.new(ssl_key, true, :pkcs1), :privkey => AsymmetricKey.new(ssl_key, false, :pkcs1) }
123
+ return { :pubkey => AsymmetricKey.new(ssl_key, true, :pkcs1),
124
+ :privkey => AsymmetricKey.new(ssl_key, false, :pkcs1) }
108
125
  end
109
126
 
110
127
  def self.generate_ssl_kp
111
128
  return Tem::CryptoAbi::AsymmetricKey.generate_ssl_kp
112
129
  end
113
130
 
131
+ def self.generate_ssl_sk
132
+ return Tem::CryptoAbi::SymmetricKey.generate_ssl_sk
133
+ end
134
+
135
+ # Wraps a TEM asymmetric key.
114
136
  class AsymmetricKey
115
137
  attr_reader :ssl_key
116
138
 
@@ -131,9 +153,11 @@ module Tem::CryptoAbi
131
153
  self.to_array.to_yaml.to_s
132
154
  end
133
155
 
156
+ # Generate an asymmetric OpenSSL key pair
134
157
  def self.generate_ssl_kp
135
158
  return OpenSSL::PKey::RSA.generate(2048, 65537)
136
159
  end
160
+
137
161
  def initialize(ssl_key, is_public, padding_type)
138
162
  @ssl_key = ssl_key
139
163
  @is_public = is_public ? true : false
@@ -188,29 +212,53 @@ module Tem::CryptoAbi
188
212
  end
189
213
 
190
214
  def encrypt(data)
191
- encrypt_decrypt(data, @size - @padding_bytes, @is_public ? :public_encrypt : :private_encrypt)
215
+ encrypt_decrypt data, @size - @padding_bytes,
216
+ @is_public ? :public_encrypt : :private_encrypt
192
217
  end
193
218
 
194
219
  def decrypt(data)
195
- encrypt_decrypt(data, @size, @is_public ? :public_decrypt : :private_decrypt)
220
+ encrypt_decrypt data, @size,
221
+ @is_public ? :public_decrypt : :private_decrypt
196
222
  end
197
223
 
198
224
  def sign(data)
199
- in_data = if data.kind_of? String then data else data.pack('C*') end
225
+ data = data.pack 'C*' if data.respond_to? :pack
200
226
  # PKCS1-padding is forced in by openssl... sigh!
201
- out_data = @ssl_key.sign OpenSSL::Digest::SHA1.new, in_data
202
- if data.kind_of? String then out_data else out_data.unpack('C*') end
227
+ out_data = @ssl_key.sign OpenSSL::Digest::SHA1.new, data
228
+ data.respond_to?(:pack) ? out_data : out_data.unpack('C*')
203
229
  end
204
230
 
205
231
  def verify(data, signature)
206
- in_data = if data.kind_of? String then data else data.pack('C*') end
207
- in_signature = if signature.kind_of? String then signature else signature.pack('C*') end
232
+ data = data.pack 'C*' if data.respond_to? :pack
233
+ signature = signature.pack 'C*' if signature.respond_to? :pack
208
234
  # PKCS1-padding is forced in by openssl... sigh!
209
- @ssl_key.verify OpenSSL::Digest::SHA1.new, in_signature, in_data
235
+ @ssl_key.verify OpenSSL::Digest::SHA1.new, signature, data
210
236
  end
211
237
 
212
238
  def is_public?
213
239
  @is_public
214
240
  end
215
- end
241
+ end
242
+
243
+ # Wraps a TEM symmetric key
244
+ def SymmetricKey
245
+ def initialize(ssl_key)
246
+ @key = ssl_key
247
+ @cipher = OpenSSL::Cipher::Cipher.new 'aes-128-ecb'
248
+ @cipher.key = @key
249
+ @cipher.iv = "\0" * 16
250
+ end
251
+
252
+ def encrypt(data)
253
+ end
254
+
255
+ def decrypt(data)
256
+ end
257
+
258
+ def sign(data)
259
+ end
260
+
261
+ def verify(data)
262
+ end
263
+ end
216
264
  end
data/lib/tem/keys.rb CHANGED
@@ -1,21 +1,19 @@
1
1
  module Tem::Keys
2
2
  def devchip_generate_key_pair
3
- response = issue_apdu [0x00, 0x40, 0x00, 0x00, 0x00].flatten
4
- tem_error(response) if failure_code(response)
5
- return { :privkey_id => read_tem_byte(response, 0), :pubkey_id => read_tem_byte(response, 1) }
3
+ response = @transport.applet_apdu! :ins => 0x40
4
+ return { :privkey_id => read_tem_byte(response, 0),
5
+ :pubkey_id => read_tem_byte(response, 1) }
6
6
  end
7
7
 
8
8
  def devchip_release_key(key_id)
9
- response = issue_apdu [0x00, 0x41, to_tem_byte(key_id), 0x00, 0x00].flatten
10
- tem_error(response) if failure_code(response)
9
+ @transport.applet_apdu! :ins => 0x41, :p1 => key_id
11
10
  return true
12
11
  end
13
12
 
14
13
  def devchip_save_key(key_id)
15
- response = issue_apdu [0x00, 0x43, to_tem_byte(key_id), 0x00, 0x00].flatten
16
- tem_error(response) if failure_code(response)
17
-
18
- buffer_id, buffer_length = read_tem_byte(response, 0), read_tem_short(response, 1)
14
+ response = @transport.applet_apdu! :ins => 0x43, :p1 => key_id
15
+ buffer_id = read_tem_byte response, 0
16
+ buffer_length = read_tem_short response, 1
19
17
  key_buffer = read_buffer buffer_id
20
18
  release_buffer buffer_id
21
19
 
@@ -24,35 +22,36 @@ module Tem::Keys
24
22
 
25
23
  def devchip_encrypt_decrypt(data, key_id, opcode)
26
24
  buffer_id = post_buffer data
27
- response = issue_apdu [0x00, opcode, to_tem_byte(key_id), to_tem_byte(buffer_id), 0x00].flatten
28
- release_buffer buffer_id
29
- tem_error(response) if failure_code(response)
25
+ begin
26
+ response = @transport.applet_apdu! :ins => opcode, :p1 => key_id,
27
+ :p2 => buffer_id
28
+ ensure
29
+ release_buffer buffer_id
30
+ end
30
31
 
31
- buffer_id, buffer_length = read_tem_byte(response, 0), read_tem_short(response, 1)
32
+ buffer_id = read_tem_byte response, 0
33
+ buffer_length = read_tem_short response, 1
32
34
  data_buffer = read_buffer buffer_id
33
35
  release_buffer buffer_id
34
36
 
35
37
  return data_buffer[0...buffer_length]
36
38
  end
37
39
  def devchip_encrypt(data, key_id)
38
- devchip_encrypt_decrypt(data, key_id, 0x44)
40
+ devchip_encrypt_decrypt data, key_id, 0x44
39
41
  end
40
42
  def devchip_decrypt(data, key_id)
41
- devchip_encrypt_decrypt(data, key_id, 0x45)
43
+ devchip_encrypt_decrypt data, key_id, 0x45
42
44
  end
43
45
 
44
46
  def stat_keys
45
- apdu = [0x00, 0x27, 0x01, 0x00, 0x00].flatten
46
- response = issue_apdu apdu
47
- tem_error(response) if failure_code(response)
48
- response = reply_data(response)
49
- key_types = {0x99 => :symmetric, 0x55 => :private, 0xAA => :public}
47
+ response = @transport.applet_apdu! :ins => 0x27, :p1 => 0x01
48
+ key_types = { 0x99 => :symmetric, 0x55 => :private, 0xAA => :public }
50
49
  stat = {:keys => {}}
51
50
  offset = 0
52
51
  while offset < response.length do
53
52
  stat[:keys][read_tem_ubyte(response, offset)] =
54
- {:type => key_types[read_tem_ubyte(response, offset + 1)],
55
- :bits => read_tem_ushort(response, offset + 2)}
53
+ { :type => key_types[read_tem_ubyte(response, offset + 1)],
54
+ :bits => read_tem_ushort(response, offset + 2) }
56
55
  offset += 4
57
56
  end
58
57
  return stat