costan-tem_ruby 0.10.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +45 -0
- data/LICENSE +21 -0
- data/Manifest +75 -0
- data/README +8 -0
- data/Rakefile +23 -0
- data/bin/tem_bench +9 -0
- data/bin/tem_ca +13 -0
- data/bin/tem_irb +11 -0
- data/bin/tem_proxy +65 -0
- data/bin/tem_stat +35 -0
- data/dev_ca/ca_cert.cer +0 -0
- data/dev_ca/ca_cert.pem +32 -0
- data/dev_ca/ca_key.pem +27 -0
- data/dev_ca/config.yml +14 -0
- data/lib/tem/_cert.rb +158 -0
- data/lib/tem/apdus/buffers.rb +89 -0
- data/lib/tem/apdus/keys.rb +64 -0
- data/lib/tem/apdus/lifecycle.rb +13 -0
- data/lib/tem/apdus/tag.rb +38 -0
- data/lib/tem/auto_conf.rb +25 -0
- data/lib/tem/builders/abi.rb +482 -0
- data/lib/tem/builders/assembler.rb +314 -0
- data/lib/tem/builders/crypto.rb +124 -0
- data/lib/tem/builders/isa.rb +120 -0
- data/lib/tem/ca.rb +114 -0
- data/lib/tem/definitions/abi.rb +65 -0
- data/lib/tem/definitions/assembler.rb +23 -0
- data/lib/tem/definitions/isa.rb +188 -0
- data/lib/tem/ecert.rb +77 -0
- data/lib/tem/hive.rb +18 -0
- data/lib/tem/keys/asymmetric.rb +116 -0
- data/lib/tem/keys/key.rb +48 -0
- data/lib/tem/keys/symmetric.rb +47 -0
- data/lib/tem/sec_exec_error.rb +63 -0
- data/lib/tem/seclosures.rb +81 -0
- data/lib/tem/secpack.rb +107 -0
- data/lib/tem/tem.rb +31 -0
- data/lib/tem/toolkit.rb +101 -0
- data/lib/tem/transport/auto_configurator.rb +87 -0
- data/lib/tem/transport/java_card_mixin.rb +99 -0
- data/lib/tem/transport/jcop_remote_protocol.rb +59 -0
- data/lib/tem/transport/jcop_remote_server.rb +171 -0
- data/lib/tem/transport/jcop_remote_transport.rb +65 -0
- data/lib/tem/transport/pcsc_transport.rb +87 -0
- data/lib/tem/transport/transport.rb +10 -0
- data/lib/tem_ruby.rb +47 -0
- data/tem_ruby.gemspec +35 -0
- data/test/_test_cert.rb +70 -0
- data/test/builders/test_abi_builder.rb +298 -0
- data/test/tem_test_case.rb +26 -0
- data/test/tem_unit/test_tem_alu.rb +33 -0
- data/test/tem_unit/test_tem_bound_secpack.rb +51 -0
- data/test/tem_unit/test_tem_branching.rb +56 -0
- data/test/tem_unit/test_tem_crypto_asymmetric.rb +123 -0
- data/test/tem_unit/test_tem_crypto_hash.rb +35 -0
- data/test/tem_unit/test_tem_crypto_pstore.rb +53 -0
- data/test/tem_unit/test_tem_crypto_random.rb +25 -0
- data/test/tem_unit/test_tem_emit.rb +23 -0
- data/test/tem_unit/test_tem_memory.rb +48 -0
- data/test/tem_unit/test_tem_memory_compare.rb +65 -0
- data/test/tem_unit/test_tem_output.rb +32 -0
- data/test/tem_unit/test_tem_yaml_secpack.rb +47 -0
- data/test/test_driver.rb +108 -0
- data/test/test_exceptions.rb +35 -0
- data/test/transport/test_auto_configurator.rb +114 -0
- data/test/transport/test_java_card_mixin.rb +90 -0
- data/test/transport/test_jcop_remote.rb +82 -0
- data/timings/blank_bound_secpack.rb +18 -0
- data/timings/blank_sec.rb +14 -0
- data/timings/devchip_decrypt.rb +9 -0
- data/timings/post_buffer.rb +10 -0
- data/timings/simple_apdu.rb +5 -0
- data/timings/timings.rb +64 -0
- data/timings/vm_perf.rb +140 -0
- data/timings/vm_perf_bound.rb +141 -0
- metadata +201 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
# :nodoc: namespace
|
4
|
+
module Tem::Transport
|
5
|
+
|
6
|
+
# Implements the transport layer for a JCOP simulator instance.
|
7
|
+
class JcopRemoteTransport
|
8
|
+
include JavaCardMixin
|
9
|
+
include JcopRemoteProtocol
|
10
|
+
|
11
|
+
# Creates a new unconnected transport for a JCOP simulator serving TCP/IP.
|
12
|
+
#
|
13
|
+
# The options parameter must have the following keys:
|
14
|
+
# host:: the DNS name or IP of the host running the JCOP simulator
|
15
|
+
# port:: the TCP/IP port of the JCOP simulator server
|
16
|
+
def initialize(options)
|
17
|
+
@host, @port = options[:host], options[:port]
|
18
|
+
@socket = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
def exchange_apdu(apdu)
|
23
|
+
send_message @socket, :type => 1, :node => 0, :data => apdu
|
24
|
+
recv_message(@socket)[:data]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Makes a transport-level connection to the TEM.
|
28
|
+
def connect
|
29
|
+
begin
|
30
|
+
Socket.getaddrinfo(@host, @port, Socket::AF_INET,
|
31
|
+
Socket::SOCK_STREAM).each do |addr_info|
|
32
|
+
begin
|
33
|
+
@socket = Socket.new(addr_info[4], addr_info[5], addr_info[6])
|
34
|
+
@socket.connect Socket.pack_sockaddr_in(addr_info[1], addr_info[3])
|
35
|
+
break
|
36
|
+
rescue
|
37
|
+
@socket = nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
raise 'Connection refused' unless @socket
|
41
|
+
|
42
|
+
# Wait for the card to be inserted.
|
43
|
+
send_message @socket, :type => 0, :node => 0, :data => [0, 1, 0, 0]
|
44
|
+
recv_message @socket # ATR should come here, but who cares
|
45
|
+
rescue Exception
|
46
|
+
@socket = nil
|
47
|
+
raise
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Breaks down the transport-level connection to the TEM.
|
52
|
+
def disconnect
|
53
|
+
if @socket
|
54
|
+
@socket.close
|
55
|
+
@socket = nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
"#<JCOP Remote Terminal: disconnected>" if @socket.nil?
|
61
|
+
"#<JCOP Remote Terminal: #{@host}:#{@port}>"
|
62
|
+
end
|
63
|
+
end # class JcopRemoteTransport
|
64
|
+
|
65
|
+
end # module Tem::Transport
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'smartcard'
|
3
|
+
|
4
|
+
# :nodoc: namespace
|
5
|
+
module Tem::Transport
|
6
|
+
|
7
|
+
class PcscTransport
|
8
|
+
include JavaCardMixin
|
9
|
+
PCSC = Smartcard::PCSC
|
10
|
+
|
11
|
+
def initialize(options)
|
12
|
+
@options = options
|
13
|
+
@context = nil
|
14
|
+
@card = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def exchange_apdu(apdu)
|
18
|
+
xmit_apdu_string = apdu.pack('C*')
|
19
|
+
result_string = @card.transmit xmit_apdu_string, @xmit_ioreq, @recv_ioreq
|
20
|
+
return result_string.unpack('C*')
|
21
|
+
end
|
22
|
+
|
23
|
+
def connect
|
24
|
+
@context = PCSC::Context.new(PCSC::SCOPE_SYSTEM) if @context.nil?
|
25
|
+
|
26
|
+
if @options[:reader_name]
|
27
|
+
@reader_name = reader_name
|
28
|
+
else
|
29
|
+
# get the first reader
|
30
|
+
readers = @context.list_readers nil
|
31
|
+
@reader_name = readers[@options[:reader_index] || 0]
|
32
|
+
end
|
33
|
+
|
34
|
+
# get the reader's status
|
35
|
+
reader_states = PCSC::ReaderStates.new(1)
|
36
|
+
reader_states.set_reader_name_of!(0, @reader_name)
|
37
|
+
reader_states.set_current_state_of!(0, PCSC::STATE_UNKNOWN)
|
38
|
+
@context.get_status_change reader_states, 100
|
39
|
+
reader_states.acknowledge_events!
|
40
|
+
|
41
|
+
# prompt for card insertion unless that already happened
|
42
|
+
if (reader_states.current_state_of(0) & PCSC::STATE_PRESENT) == 0
|
43
|
+
puts "Please insert TEM card in reader #{@reader_name}\n"
|
44
|
+
while (reader_states.current_state_of(0) & PCSC::STATE_PRESENT) == 0 do
|
45
|
+
@context.get_status_change reader_states, PCSC::INFINITE_TIMEOUT
|
46
|
+
reader_states.acknowledge_events!
|
47
|
+
end
|
48
|
+
puts "Card detected\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
# connect to card
|
52
|
+
@card = PCSC::Card.new @context, @reader_name, PCSC::SHARE_EXCLUSIVE,
|
53
|
+
PCSC::PROTOCOL_ANY
|
54
|
+
|
55
|
+
# build the transmit / receive IoRequests
|
56
|
+
status = @card.status
|
57
|
+
@xmit_ioreq = @@xmit_iorequest[status[:protocol]]
|
58
|
+
if RUBY_PLATFORM =~ /win/ and (not RUBY_PLATFORM =~ /darwin/)
|
59
|
+
@recv_ioreq = nil
|
60
|
+
else
|
61
|
+
@recv_ioreq = PCSC::IoRequest.new
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def disconnect
|
66
|
+
unless @card.nil?
|
67
|
+
@card.disconnect PCSC::DISPOSITION_LEAVE
|
68
|
+
@card = nil
|
69
|
+
end
|
70
|
+
unless @context.nil?
|
71
|
+
@context.release
|
72
|
+
@context = nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s
|
77
|
+
"#<PC/SC Terminal: disconnected>" if @card.nil?
|
78
|
+
"#<PC/SC Terminal: #{@reader_name}>"
|
79
|
+
end
|
80
|
+
|
81
|
+
@@xmit_iorequest = {
|
82
|
+
Smartcard::PCSC::PROTOCOL_T0 => Smartcard::PCSC::IOREQUEST_T0,
|
83
|
+
Smartcard::PCSC::PROTOCOL_T1 => Smartcard::PCSC::IOREQUEST_T1,
|
84
|
+
}
|
85
|
+
end # class PcscTransport
|
86
|
+
|
87
|
+
end # module Tem::Transport
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# The transport module contains classes responsible for transferring low-level
|
2
|
+
# commands issed by the high-level TEM methods to actual TEMs, which can be
|
3
|
+
# connected to the system in various ways.
|
4
|
+
module Tem::Transport
|
5
|
+
|
6
|
+
# Shortcut for Tem::Transport::AutoConfigurator#auto_transport
|
7
|
+
def self.auto_transport
|
8
|
+
Tem::Transport::AutoConfigurator.auto_transport
|
9
|
+
end
|
10
|
+
end
|
data/lib/tem_ruby.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# gems
|
2
|
+
require 'rubygems'
|
3
|
+
require 'smartcard'
|
4
|
+
|
5
|
+
# :nodoc:
|
6
|
+
module Tem
|
7
|
+
end
|
8
|
+
|
9
|
+
# :nodoc:
|
10
|
+
module Tem::Transport
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'tem/transport/transport.rb'
|
14
|
+
require 'tem/transport/java_card_mixin.rb'
|
15
|
+
require 'tem/transport/pcsc_transport.rb'
|
16
|
+
require 'tem/transport/jcop_remote_protocol.rb'
|
17
|
+
require 'tem/transport/jcop_remote_transport.rb'
|
18
|
+
require 'tem/transport/jcop_remote_server.rb'
|
19
|
+
require 'tem/transport/auto_configurator.rb'
|
20
|
+
|
21
|
+
require 'tem/keys/key.rb'
|
22
|
+
require 'tem/keys/asymmetric.rb'
|
23
|
+
require 'tem/keys/symmetric.rb'
|
24
|
+
|
25
|
+
require 'tem/builders/abi.rb'
|
26
|
+
require 'tem/builders/assembler.rb'
|
27
|
+
require 'tem/builders/crypto.rb'
|
28
|
+
require 'tem/builders/isa.rb'
|
29
|
+
|
30
|
+
require 'tem/definitions/abi.rb'
|
31
|
+
require 'tem/definitions/isa.rb'
|
32
|
+
require 'tem/definitions/assembler.rb'
|
33
|
+
|
34
|
+
require 'tem/auto_conf.rb'
|
35
|
+
require 'tem/apdus/buffers.rb'
|
36
|
+
require 'tem/apdus/keys.rb'
|
37
|
+
require 'tem/apdus/lifecycle.rb'
|
38
|
+
require 'tem/apdus/tag.rb'
|
39
|
+
|
40
|
+
require 'tem/ca.rb'
|
41
|
+
require 'tem/ecert.rb'
|
42
|
+
require 'tem/hive.rb'
|
43
|
+
require 'tem/sec_exec_error.rb'
|
44
|
+
require 'tem/seclosures.rb'
|
45
|
+
require 'tem/secpack.rb'
|
46
|
+
require 'tem/toolkit.rb'
|
47
|
+
require 'tem/tem.rb'
|
data/tem_ruby.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{tem_ruby}
|
5
|
+
s.version = "0.10.2"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Victor Costan"]
|
9
|
+
s.date = %q{2009-05-31}
|
10
|
+
s.description = %q{TEM (Trusted Execution Module) driver, written in and for ruby.}
|
11
|
+
s.email = %q{victor@costan.us}
|
12
|
+
s.executables = ["tem_bench", "tem_ca", "tem_irb", "tem_proxy", "tem_stat"]
|
13
|
+
s.extra_rdoc_files = ["bin/tem_bench", "bin/tem_ca", "bin/tem_irb", "bin/tem_proxy", "bin/tem_stat", "CHANGELOG", "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/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/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/transport/auto_configurator.rb", "lib/tem/transport/java_card_mixin.rb", "lib/tem/transport/jcop_remote_protocol.rb", "lib/tem/transport/jcop_remote_server.rb", "lib/tem/transport/jcop_remote_transport.rb", "lib/tem/transport/pcsc_transport.rb", "lib/tem/transport/transport.rb", "lib/tem_ruby.rb", "LICENSE", "README"]
|
14
|
+
s.files = ["bin/tem_bench", "bin/tem_ca", "bin/tem_irb", "bin/tem_proxy", "bin/tem_stat", "CHANGELOG", "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/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/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/transport/auto_configurator.rb", "lib/tem/transport/java_card_mixin.rb", "lib/tem/transport/jcop_remote_protocol.rb", "lib/tem/transport/jcop_remote_server.rb", "lib/tem/transport/jcop_remote_transport.rb", "lib/tem/transport/pcsc_transport.rb", "lib/tem/transport/transport.rb", "lib/tem_ruby.rb", "LICENSE", "Manifest", "Rakefile", "README", "tem_ruby.gemspec", "test/_test_cert.rb", "test/builders/test_abi_builder.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_asymmetric.rb", "test/tem_unit/test_tem_crypto_hash.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_driver.rb", "test/test_exceptions.rb", "test/transport/test_auto_configurator.rb", "test/transport/test_java_card_mixin.rb", "test/transport/test_jcop_remote.rb", "timings/blank_bound_secpack.rb", "timings/blank_sec.rb", "timings/devchip_decrypt.rb", "timings/post_buffer.rb", "timings/simple_apdu.rb", "timings/timings.rb", "timings/vm_perf.rb", "timings/vm_perf_bound.rb"]
|
15
|
+
s.homepage = %q{http://tem.rubyforge.org}
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Tem_ruby", "--main", "README"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{tem}
|
19
|
+
s.rubygems_version = %q{1.3.3}
|
20
|
+
s.summary = %q{TEM (Trusted Execution Module) driver, written in and for ruby.}
|
21
|
+
s.test_files = ["test/builders/test_abi_builder.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_asymmetric.rb", "test/tem_unit/test_tem_crypto_hash.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_driver.rb", "test/test_exceptions.rb", "test/transport/test_auto_configurator.rb", "test/transport/test_java_card_mixin.rb", "test/transport/test_jcop_remote.rb"]
|
22
|
+
|
23
|
+
if s.respond_to? :specification_version then
|
24
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
25
|
+
s.specification_version = 3
|
26
|
+
|
27
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
28
|
+
s.add_runtime_dependency(%q<smartcard>, [">= 0.3.0"])
|
29
|
+
else
|
30
|
+
s.add_dependency(%q<smartcard>, [">= 0.3.0"])
|
31
|
+
end
|
32
|
+
else
|
33
|
+
s.add_dependency(%q<smartcard>, [">= 0.3.0"])
|
34
|
+
end
|
35
|
+
end
|
data/test/_test_cert.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Victor Costan:
|
2
|
+
# dropped because it wasn't hooked up to the rest of the code
|
3
|
+
# preserved to move all the features into the new ca.rb / ecert.rb
|
4
|
+
|
5
|
+
require 'tem_ruby'
|
6
|
+
require 'test/unit'
|
7
|
+
require 'openssl'
|
8
|
+
|
9
|
+
# Integration work by Victor Costan
|
10
|
+
|
11
|
+
|
12
|
+
#Author: Jorge de la Garza (MIT '08), mongoose08@alum.mit.edu
|
13
|
+
#This unit test does the following:
|
14
|
+
#1. Makes issuer's (manufacturer's) X.509 certificate, which is self-signed.
|
15
|
+
#2. Makes subject's (TEM's) X.509 certificate, which is signed with the issuers private key.
|
16
|
+
#3. Constructs the TEMTag from the subject's:
|
17
|
+
# -Serial number (4 bytes)
|
18
|
+
# -Not before date (4 bytes)
|
19
|
+
# -Not after date (4 bytes)
|
20
|
+
# -Modulus (256 bytes)
|
21
|
+
# -Public key exp (3 bytes)
|
22
|
+
# -Signature (256 bytes)
|
23
|
+
#4. Sets the TEMTag on the TEM
|
24
|
+
#5. Reads back the TEMTag
|
25
|
+
#6. Constructs a new X.509 certificate from the TEMTag and asserts that this is equal to the original certificate
|
26
|
+
|
27
|
+
class CertTest < Test::Unit::TestCase
|
28
|
+
def setup
|
29
|
+
@tem = Tem.auto_tem
|
30
|
+
|
31
|
+
@tem.kill
|
32
|
+
@tem.activate
|
33
|
+
end
|
34
|
+
|
35
|
+
def teardown
|
36
|
+
@tem.disconnect unless @tem.nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_cert
|
40
|
+
#Create issuer's (manufacturer's) certificate
|
41
|
+
issuer_key = OpenSSL::PKey::RSA.new 2048, 0x10001
|
42
|
+
issuer_cert = Tem::Cert.create_issuer_cert(issuer_key)
|
43
|
+
|
44
|
+
#Create subject's (TEM's) certificate
|
45
|
+
subject_key = OpenSSL::PKey::RSA.new 2048, 0x10001
|
46
|
+
subject_cert = Tem::Cert.create_subject_cert(subject_key, issuer_key, issuer_cert)
|
47
|
+
|
48
|
+
#Create the tag that will go on the TEM from it's certificate
|
49
|
+
written_tag = Tem::Cert.create_tag_from_cert(subject_cert)
|
50
|
+
|
51
|
+
#Set the tag on the TEM, assert that tag read = tag written
|
52
|
+
@tem.set_tag(written_tag)
|
53
|
+
read_tag = @tem.get_tag[2..-1] #chop off first two bytes, TEM puts firmware version on front of written tag
|
54
|
+
assert_equal written_tag, read_tag, 'error in posted tag data'
|
55
|
+
|
56
|
+
#Now reconstruct original certificate from tag data
|
57
|
+
read_cert = Tem::Cert.create_cert_from_tag(read_tag, issuer_cert)
|
58
|
+
read_cert.sign issuer_key, OpenSSL::Digest::SHA1.new
|
59
|
+
|
60
|
+
assert_equal Tem::Cert.extract_sig_from_cert(subject_cert), Tem::Cert.extract_sig_from_cert(read_cert), 'signatures do not match'
|
61
|
+
#If the signature of the original certificate matches the signature of the reconstructed certificate,
|
62
|
+
#we can be pretty much certain that the certificates are identical
|
63
|
+
|
64
|
+
#TODO: PROBLEM:
|
65
|
+
#There is no way to set the signature to a known value.
|
66
|
+
#The only way to set the signature is to sign the certificate, and only the issuer (manufacturer) can do this.
|
67
|
+
#This means that the manufacturer has to be contacted every time the user wants to verify the TEM's certificate,
|
68
|
+
#and this may not be practical.
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,298 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
require 'tem_ruby'
|
5
|
+
|
6
|
+
class AbiBuilderTest < Test::Unit::TestCase
|
7
|
+
class Wrapped
|
8
|
+
attr_accessor :p, :q, :n
|
9
|
+
attr_accessor :d # Derived value.
|
10
|
+
attr_accessor :c # Constructor value.
|
11
|
+
|
12
|
+
def initialize(ctor_value = 'ctor default')
|
13
|
+
self.c = ctor_value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Multi
|
18
|
+
attr_accessor :p, :q, :n
|
19
|
+
attr_accessor :a, :b, :c
|
20
|
+
attr_accessor :str, :const
|
21
|
+
end
|
22
|
+
|
23
|
+
module Abi
|
24
|
+
Tem::Builders::Abi.define_abi self do |abi|
|
25
|
+
abi.fixed_length_number :byte, 1, :signed => true
|
26
|
+
abi.fixed_length_number :ubyte, 1, :signed => false
|
27
|
+
|
28
|
+
abi.fixed_length_number :word, 2, :signed => true, :big_endian => false
|
29
|
+
abi.fixed_length_number :netword, 2, :signed => true, :big_endian => true
|
30
|
+
|
31
|
+
abi.fixed_length_number :dword, 4, :signed => true, :big_endian => true
|
32
|
+
abi.fixed_length_number :udword, 4, :signed => false, :big_endian => false
|
33
|
+
|
34
|
+
abi.variable_length_number :vln, :word, :signed => false,
|
35
|
+
:big_endian => false
|
36
|
+
abi.variable_length_number :net_vln, :netword, :signed => false,
|
37
|
+
:big_endian => true
|
38
|
+
abi.packed_variable_length_numbers :packed, :word, [:p, :q, :n],
|
39
|
+
:signed => false,
|
40
|
+
:big_endian => false
|
41
|
+
abi.packed_variable_length_numbers :net_packed, :netword,
|
42
|
+
[:x, :y, :z, :a],
|
43
|
+
:signed => false,
|
44
|
+
:big_endian => true
|
45
|
+
abi.fixed_length_string :mac_id, 6
|
46
|
+
abi.object_wrapper :wrapped_raw, Wrapped, [:packed, nil]
|
47
|
+
abi.object_wrapper :wrapped, Wrapped, [:packed, nil],
|
48
|
+
:to => lambda { |o| w = Wrapped.new
|
49
|
+
w.p, w.q, w.n = o.p, o.q, o.n * 100
|
50
|
+
w },
|
51
|
+
:read => lambda { |o| w = Wrapped.new(o.c); w.d = o.p * o.q; w },
|
52
|
+
:new => lambda { |klass| klass.new('hook-new') }
|
53
|
+
abi.object_wrapper :multi, Multi,
|
54
|
+
[:packed, nil,:packed, { :p => :a, :q => :b, :n => :c},
|
55
|
+
:mac_id, :str, 'constant string', :const]
|
56
|
+
|
57
|
+
abi.conditional_wrapper :conditional, 2,
|
58
|
+
[{:tag => [0x59, 0xAF], :class => String, :type => :mac_id},
|
59
|
+
{:tag => [0x59, 0xAC], :class => Integer, :type => :net_vln,
|
60
|
+
:predicate => lambda { |n| n % 2 == 1 } },
|
61
|
+
{:tag => [0x59, 0xAD], :type => :dword,
|
62
|
+
:predicate => lambda { |n| n % 3 == 1 } }]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def setup
|
67
|
+
@garbage = [0xFD, 0xFC, 0xFD, 0xFC, 0xFD] * 5
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_fixed_and_variable_length_number_encoding
|
71
|
+
[
|
72
|
+
[:byte, 0, [0]], [:byte, 127, [127]],
|
73
|
+
[:byte, -1, [255]], [:byte, -127, [129]], [:byte, -128, [128]],
|
74
|
+
[:byte, 128, nil], [:byte, -129, nil],
|
75
|
+
|
76
|
+
[:word, 0, [0, 0]], [:word, 127, [127, 0]], [:word, 128, [128, 0]],
|
77
|
+
[:word, 256, [0, 1]], [:word, 32767, [255, 127]],
|
78
|
+
[:word, -1, [255, 255]], [:word, -127, [129, 255]],
|
79
|
+
[:word, -128, [128, 255]], [:word, -256, [0, 255]],
|
80
|
+
[:word, -32767, [1, 128], [:word, -32768, [0, 128]]],
|
81
|
+
[:word, 32768, nil], [:byte, -32769, nil],
|
82
|
+
|
83
|
+
[:netword, 0, [0, 0]], [:netword, 127, [0, 127]],
|
84
|
+
[:netword, 128, [0, 128]],
|
85
|
+
[:netword, 256, [1, 0]], [:netword, 32767, [127, 255]],
|
86
|
+
[:netword, -1, [255, 255]], [:netword, -127, [255, 129]],
|
87
|
+
[:netword, -128, [255, 128]], [:netword, -256, [255, 0]],
|
88
|
+
[:netword, -32767, [128, 1], [:netword, -32768, [128, 0]]],
|
89
|
+
[:netword, 32768, nil], [:netword, -32769, nil],
|
90
|
+
|
91
|
+
[:dword, 0x12345678, [0x12, 0x34, 0x56, 0x78]],
|
92
|
+
[:udword, 0x12345678, [0x78, 0x56, 0x34, 0x12]],
|
93
|
+
[:udword, 0xFFFFFFFF, [255, 255, 255, 255]],
|
94
|
+
[:udword, 0xFFFFFFFE, [254, 255, 255, 255]],
|
95
|
+
|
96
|
+
[:vln, 0, [0x01, 0x00, 0x00]], [:vln, 1, [0x01, 0x00, 0x01]],
|
97
|
+
[:vln, 256, [0x02, 0x00, 0x00, 0x01]],
|
98
|
+
[:vln, 65537, [0x03, 0x00, 0x01, 0x00, 0x01]],
|
99
|
+
[:vln, 0x12345678, [0x04, 0x00, 0x78, 0x56, 0x34, 0x12]],
|
100
|
+
[:vln, 0xFFFFFFFF, [0x04, 0x00, 255, 255, 255, 255]],
|
101
|
+
[:vln, 0xFFFFFFFE, [0x04, 0x00, 254, 255, 255, 255]],
|
102
|
+
|
103
|
+
[:net_vln, 0, [0x00, 0x01, 0x00]], [:net_vln, 1, [0x00, 0x01, 0x01]],
|
104
|
+
[:net_vln, 256, [0x00, 0x02, 0x01, 0x00]],
|
105
|
+
[:net_vln, 65537, [0x00, 0x03, 0x01, 0x00, 0x01]],
|
106
|
+
[:net_vln, 0x12345678, [0x00, 0x04, 0x12, 0x34, 0x56, 0x78]],
|
107
|
+
[:net_vln, 0xFFFFFFFF, [0x00, 0x04, 255, 255, 255, 255]],
|
108
|
+
[:net_vln, 0xFFFFFFFE, [0x00, 0x04, 255, 255, 255, 254]],
|
109
|
+
].each do |test_line|
|
110
|
+
type, number, array = *test_line
|
111
|
+
if array
|
112
|
+
assert_equal array, Abi.send(:"to_#{type}", number),
|
113
|
+
"#{type} failed on Ruby number -> array"
|
114
|
+
assert_equal array, Abi.send(:"to_#{type}",
|
115
|
+
OpenSSL::BN.new(number.to_s)),
|
116
|
+
"#{type} failed on OpenSSL number -> array"
|
117
|
+
assert_equal number, Abi.send(:"read_#{type}", @garbage + array,
|
118
|
+
@garbage.length)
|
119
|
+
if Abi.respond_to? :"#{type}_length"
|
120
|
+
assert_equal array.length, Abi.send(:"#{type}_length"),
|
121
|
+
"#{type} failed on length"
|
122
|
+
elsif Abi.respond_to? :"read_#{type}_length"
|
123
|
+
assert_equal array.length,
|
124
|
+
Abi.send(:"read_#{type}_length", @garbage + array,
|
125
|
+
@garbage.length),
|
126
|
+
"#{type} failed on read_#{type}_length"
|
127
|
+
else
|
128
|
+
flunk "#{type} does not provide _length or read_#{type}_length"
|
129
|
+
end
|
130
|
+
else
|
131
|
+
assert_raise RuntimeError do
|
132
|
+
assert_equal array, Abi.send(:"to_#{type}", number)
|
133
|
+
end
|
134
|
+
assert_raise RuntimeError do
|
135
|
+
assert_equal array, Abi.send(:"to_#{type}",
|
136
|
+
OpenSSL::BN.new(number.to_s))
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
assert_equal [255, 255, 255, 255], Abi.signed_to_udword(-1),
|
142
|
+
'Failed on signed_to_udword'
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_packed_number_encoding
|
146
|
+
packed = { :p => 0x123, :q => 0xABCDEF, :n => 5 }
|
147
|
+
gold_packed = [0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x23, 0x01, 0xEF, 0xCD,
|
148
|
+
0xAB, 0x05]
|
149
|
+
assert_equal gold_packed, Abi.to_packed(packed), 'packed'
|
150
|
+
assert_equal packed, Abi.read_packed(@garbage + gold_packed,
|
151
|
+
@garbage.length), 'packed'
|
152
|
+
assert_equal gold_packed.length,
|
153
|
+
Abi.read_packed_length(@garbage + gold_packed,
|
154
|
+
@garbage.length),
|
155
|
+
'read_packed_length'
|
156
|
+
|
157
|
+
net_packed = { :x => 0x271, :y => 0x314159, :z => 0, :a => 0x5AA5 }
|
158
|
+
gold_net_packed = [0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02,
|
159
|
+
0x02, 0x71, 0x31, 0x41, 0x59, 0x00, 0x5A, 0xA5 ]
|
160
|
+
assert_equal gold_net_packed, Abi.to_net_packed(net_packed), 'net-packed'
|
161
|
+
assert_equal net_packed, Abi.read_net_packed(@garbage + gold_net_packed,
|
162
|
+
@garbage.length),
|
163
|
+
'net_packed'
|
164
|
+
assert_equal gold_net_packed.length,
|
165
|
+
Abi.read_net_packed_length(@garbage + gold_net_packed,
|
166
|
+
@garbage.length),
|
167
|
+
'read_net_packed_length'
|
168
|
+
components = Abi.net_packed_components
|
169
|
+
assert_equal [:x, :y, :z, :a], components,
|
170
|
+
'incorrect result from _components'
|
171
|
+
assert_raise TypeError, '_components result is mutable' do
|
172
|
+
components[0] = :w
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_fixed_length_string_encoding
|
177
|
+
[
|
178
|
+
[:mac_id, "abcdef", nil, [?a, ?b, ?c, ?d, ?e, ?f]],
|
179
|
+
[:mac_id, "abc", "abc\0\0\0", [?a, ?b, ?c, 0, 0, 0]],
|
180
|
+
[:mac_id, "", "\0\0\0\0\0\0", [0, 0, 0, 0, 0, 0]],
|
181
|
+
[:mac_id, "abcdefg", nil, nil],
|
182
|
+
[:mac_id, [?a, ?b, ?c, ?d, ?e, ?f], "abcdef", [?a, ?b, ?c, ?d, ?e, ?f]],
|
183
|
+
[:mac_id, [?a, ?b, ?c], "abc\0\0\0", [?a, ?b, ?c, 0, 0, 0]],
|
184
|
+
[:mac_id, [], "\0\0\0\0\0\0", [0, 0, 0, 0, 0, 0]],
|
185
|
+
[:mac_id, [?a, ?b, ?c, ?d, ?e, ?f, ?g], nil, nil],
|
186
|
+
].each do |line|
|
187
|
+
type, source, string, array = *line
|
188
|
+
string ||= source
|
189
|
+
if array
|
190
|
+
assert_equal array, Abi.send(:"to_#{type}", source),
|
191
|
+
"#{type} failed on string -> array"
|
192
|
+
assert_equal string, Abi.send(:"read_#{type}", @garbage + array,
|
193
|
+
@garbage.length)
|
194
|
+
else
|
195
|
+
assert_raise RuntimeError do
|
196
|
+
assert_equal array, Abi.send(:"to_#{type}", source)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_object_wrapper_directs
|
203
|
+
packed = { :p => 2301, :q => 4141, :n => 60 }
|
204
|
+
gold_packed = Abi.to_packed packed
|
205
|
+
wrapped = Abi.read_wrapped_raw @garbage + gold_packed, @garbage.length
|
206
|
+
assert_equal Wrapped, wrapped.class,
|
207
|
+
'Reading wrapped object instantiated wrong class'
|
208
|
+
assert_equal [packed[:p], packed[:q], packed[:n], nil, 'ctor default'],
|
209
|
+
[wrapped.p, wrapped.q, wrapped.n, wrapped.d, wrapped.c],
|
210
|
+
'Reading wrapped object gave wrong attributes'
|
211
|
+
assert_equal gold_packed.length,
|
212
|
+
Abi.read_wrapped_raw_length(@garbage + gold_packed,
|
213
|
+
@garbage.length),
|
214
|
+
'Reading wrapped object length'
|
215
|
+
assert_equal gold_packed, Abi.to_wrapped_raw(wrapped),
|
216
|
+
'Wrapped object -> array'
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_object_wrapper_schema
|
220
|
+
packed = { :p => 2301, :q => 4141, :n => 60 }
|
221
|
+
xpacked = { :p => 6996, :q => 1331, :n => 22 }
|
222
|
+
gold_multi = Abi.to_packed(packed) + Abi.to_packed(xpacked) +
|
223
|
+
Abi.to_mac_id("abc")
|
224
|
+
multi = Abi.read_multi @garbage + gold_multi, @garbage.length
|
225
|
+
assert_equal Multi, multi.class,
|
226
|
+
'Reading wrapped object instantiated wrong class'
|
227
|
+
assert_equal [packed[:p], packed[:q], packed[:n],
|
228
|
+
xpacked[:p], xpacked[:q], xpacked[:n], "abc\0\0\0",
|
229
|
+
"constant string"],
|
230
|
+
[multi.p, multi.q, multi.n, multi.a, multi.b, multi.c,
|
231
|
+
multi.str, multi.const],
|
232
|
+
'Reading wrapped object gave wrong attributes'
|
233
|
+
assert_equal gold_multi, Abi.to_multi(multi),
|
234
|
+
'Wrapped object -> array'
|
235
|
+
assert_equal gold_multi.length,
|
236
|
+
Abi.read_multi_length(@garbage + gold_multi, @garbage.length),
|
237
|
+
'Reading wrapped object length'
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_object_wrapper_hooks
|
241
|
+
packed = { :p => 2301, :q => 4141, :n => 60 }
|
242
|
+
gold_packed = Abi.to_packed packed
|
243
|
+
wrapped = Abi.read_wrapped @garbage + gold_packed, @garbage.length
|
244
|
+
assert_equal Wrapped, wrapped.class,
|
245
|
+
'Reading wrapped object instantiated wrong class'
|
246
|
+
assert_equal [nil, nil, nil, packed[:p] * packed[:q], 'hook-new'],
|
247
|
+
[wrapped.p, wrapped.q, wrapped.n, wrapped.d, wrapped.c],
|
248
|
+
'Reading wrapped object with hook gave wrong attributes'
|
249
|
+
|
250
|
+
wrapped = Abi.read_wrapped_raw gold_packed, 0
|
251
|
+
packed[:n] *= 100
|
252
|
+
gold_packed = Abi.to_packed packed
|
253
|
+
assert_equal gold_packed, Abi.to_wrapped(wrapped),
|
254
|
+
'Wrapped object -> array (with hook)'
|
255
|
+
|
256
|
+
assert_equal gold_packed.length,
|
257
|
+
Abi.read_packed_length(@garbage + gold_packed,
|
258
|
+
@garbage.length),
|
259
|
+
'Reading wrapped object length'
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_conditional_wrapper
|
263
|
+
[
|
264
|
+
[:conditional, "abcdef", [0x59, 0xAF, ?a, ?b, ?c, ?d, ?e, ?f]],
|
265
|
+
[:conditional, 3, [0x59, 0xAC, 0x00, 0x01, 0x03]],
|
266
|
+
[:conditional, 4, [0x59, 0xAD, 0x00, 0x00, 0x00, 0x04]],
|
267
|
+
[:conditional, OpenSSL::BN.new('7'), [0x59, 0xAD, 0x00, 0x00, 0x00, 0x07]],
|
268
|
+
[:conditional, 6, nil]
|
269
|
+
].each do |test_line|
|
270
|
+
type, object, array = *test_line
|
271
|
+
if array
|
272
|
+
assert_equal array, Abi.send(:"to_#{type}", object),
|
273
|
+
"Object #{object.inspect} -> array"
|
274
|
+
assert_equal object, Abi.send(:"read_#{type}", @garbage + array,
|
275
|
+
@garbage.length)
|
276
|
+
assert_equal array.length,
|
277
|
+
Abi.send(:"read_#{type}_length", @garbage + array,
|
278
|
+
@garbage.length),
|
279
|
+
"#{type} failed on read_#{type}_length"
|
280
|
+
else
|
281
|
+
assert_raise RuntimeError do
|
282
|
+
assert_equal array, Abi.send(:"to_#{type}", object)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def test_length
|
289
|
+
[[:byte, 1], [:ubyte, 1],
|
290
|
+
[:word, 2], [:netword, 2],
|
291
|
+
[:dword, 4], [:udword, 4],
|
292
|
+
[:mac_id, 6]
|
293
|
+
].each do |test_line|
|
294
|
+
assert_equal test_line.last, Abi.send(:"#{test_line.first}_length"),
|
295
|
+
"length failed for #{test_line.first}"
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|