tem_ruby 0.9.2 → 0.10.0

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