smartcard 0.4.1-x86-mswin32-60 → 0.4.3-x86-mswin32-60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +4 -0
- data/Manifest +13 -6
- data/Rakefile +6 -4
- data/lib/smartcard/gp/asn1_ber.rb +199 -0
- data/lib/smartcard/gp/cap_loader.rb +88 -0
- data/lib/smartcard/gp/des.rb +68 -0
- data/lib/smartcard/gp/gp_card_mixin.rb +364 -5
- data/lib/smartcard/iso/iso_card_mixin.rb +13 -3
- data/lib/smartcard/iso/jcop_remote_server.rb +14 -5
- data/lib/smartcard/iso/pcsc_transport.rb +8 -1
- data/lib/smartcard/pcsc.so +0 -0
- data/lib/smartcard.rb +3 -0
- data/smartcard.gemspec +8 -5
- data/test/gp/asn1_ber_test.rb +116 -0
- data/test/gp/cap_loader_test.rb +24 -0
- data/test/gp/des_test.rb +39 -0
- data/test/gp/gp_card_mixin_test.rb +194 -5
- data/test/gp/hello.apdu +1 -0
- data/test/gp/hello.cap +0 -0
- data/test/iso/iso_card_mixin_test.rb +9 -8
- data/test/iso/jcop_remote_test.rb +4 -1
- metadata +36 -13
@@ -0,0 +1,116 @@
|
|
1
|
+
# Author:: Victor Costan
|
2
|
+
# Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
|
3
|
+
# License:: MIT
|
4
|
+
|
5
|
+
require 'smartcard'
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
|
9
|
+
class Asn1BerTest < Test::Unit::TestCase
|
10
|
+
Asn1Ber = Smartcard::Gp::Asn1Ber
|
11
|
+
|
12
|
+
def test_tag
|
13
|
+
prefix = [0x03, 0x14, 0x15]
|
14
|
+
[
|
15
|
+
[[0x82], {:primitive => true, :class => :context, :number => 2}],
|
16
|
+
[[0x29], {:primitive => false, :class => :universal, :number => 9}],
|
17
|
+
[[0xD9], {:primitive => true, :class => :private, :number => 0x19}],
|
18
|
+
[[0x9F, 0x65], {:primitive => true, :class => :context, :number => 0x65}],
|
19
|
+
[[0x5F, 0x81, 0x65], {:primitive => true, :class => :application,
|
20
|
+
:number => 0xE5}],
|
21
|
+
].each do |test_case|
|
22
|
+
offset, tag = Asn1Ber.decode_tag prefix + test_case.first, prefix.length
|
23
|
+
assert_equal((prefix + test_case.first).length, offset,
|
24
|
+
"Offset for #{test_case.inspect}")
|
25
|
+
assert_equal test_case.last, tag,
|
26
|
+
"Decoded tag information for #{test_case.inspect}"
|
27
|
+
assert_equal test_case.first, Asn1Ber.encode_tag(test_case.last),
|
28
|
+
"Encoded tag for #{test_case.inspect}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_length
|
33
|
+
prefix = [0x03, 0x14, 0x15]
|
34
|
+
[
|
35
|
+
[[0x12], 0x12],
|
36
|
+
[[0x82, 0x05, 0x39], 0x539],
|
37
|
+
[[0x80], :indefinite],
|
38
|
+
].each do |test_case|
|
39
|
+
offset, length = Asn1Ber.decode_length prefix + test_case.first,
|
40
|
+
prefix.length
|
41
|
+
assert_equal((prefix + test_case.first).length, offset,
|
42
|
+
"Offset for #{test_case.inspect}")
|
43
|
+
assert_equal test_case.last, length,
|
44
|
+
"Decoded length for #{test_case.inspect}"
|
45
|
+
assert_equal test_case.first, Asn1Ber.encode_length(test_case.last),
|
46
|
+
"Encoded length for #{test_case.inspect}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_value
|
51
|
+
data = (0...20).to_a
|
52
|
+
offset, value = Asn1Ber.decode_value data, 7, 4
|
53
|
+
assert_equal 7 + 4, offset, 'Offset with definite length'
|
54
|
+
assert_equal [7, 8, 9, 10], value, 'Value with definite length'
|
55
|
+
|
56
|
+
data = [0x03, 0x14, 0x15, 0x92, 0x65, 0x35, 0x00, 0x00, 0x01, 0x02, 0x03]
|
57
|
+
offset, value = Asn1Ber.decode_value data, 4, :indefinite
|
58
|
+
assert_equal 8, offset, 'Offset with indefinite length'
|
59
|
+
assert_equal [0x65, 0x35], value, 'Value with definite length'
|
60
|
+
offset, value = Asn1Ber.decode_value data, 6, :indefinite
|
61
|
+
assert_equal 8, offset, 'Offset for empty value with indefinite length'
|
62
|
+
assert_equal [], value, 'Empty value with indefinite length'
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_tlv
|
66
|
+
golden_tlv = {:primitive => true, :class => :context, :number => 4,
|
67
|
+
:value => [0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00]}
|
68
|
+
prefix = [0x03, 0x14, 0x15]
|
69
|
+
ber_tlv = [0x84, 0x08, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00]
|
70
|
+
offset, tlv = Asn1Ber.decode_tlv prefix + ber_tlv, prefix.length
|
71
|
+
assert_equal golden_tlv, tlv, 'Decoded TLV data'
|
72
|
+
assert_equal((prefix + ber_tlv).length, offset, 'Offset')
|
73
|
+
assert_equal ber_tlv, Asn1Ber.encode_tlv(golden_tlv), 'Encoded TLV data'
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_tlv_sequence
|
77
|
+
golden = [
|
78
|
+
{:number => 0x0F, :class => :application, :primitive => false,
|
79
|
+
:value => [
|
80
|
+
{:number => 4, :class => :context, :primitive => true,
|
81
|
+
:value => [0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00]},
|
82
|
+
{:number => 5, :class => :context, :primitive => false,
|
83
|
+
:value => [
|
84
|
+
{:number => 0x65, :class => :context, :primitive => true,
|
85
|
+
:value => [0xFF]}]}]}]
|
86
|
+
ber = [0x6F, 16, 0x84, 8, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
87
|
+
0xA5, 4, 0x9F, 0x65, 1, 0xFF]
|
88
|
+
assert_equal golden, Asn1Ber.decode(ber), 'Decoded sequence'
|
89
|
+
assert_equal ber, Asn1Ber.encode(golden), 'Encoded sequence'
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_visit
|
93
|
+
tlvs = [
|
94
|
+
{:number => 0x0F, :class => :application, :primitive => false,
|
95
|
+
:value => [
|
96
|
+
{:number => 4, :class => :context, :primitive => true,
|
97
|
+
:value => [0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00]},
|
98
|
+
{:number => 5, :class => :context, :primitive => false,
|
99
|
+
:value => [
|
100
|
+
{:number => 0x65, :class => :context, :primitive => true,
|
101
|
+
:value => [0xFF]}]}]}]
|
102
|
+
|
103
|
+
paths = []
|
104
|
+
Asn1Ber.visit tlvs do |path, value|
|
105
|
+
paths << path
|
106
|
+
case path
|
107
|
+
when [0x6F, 0xA5, 0x9F65]
|
108
|
+
assert_equal [0xFF], value
|
109
|
+
when [0x6F, 0x84]
|
110
|
+
assert_equal [0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00], value
|
111
|
+
end
|
112
|
+
end
|
113
|
+
assert_equal [[0x6F], [0x6F, 0x84], [0x6F, 0xA5], [0x6F, 0xA5, 0x9F65]],
|
114
|
+
paths, 'Visited paths'
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Author:: Victor Costan
|
2
|
+
# Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
|
3
|
+
# License:: MIT
|
4
|
+
|
5
|
+
require 'smartcard'
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
|
9
|
+
class CapLoaderTest < Test::Unit::TestCase
|
10
|
+
CapLoader = Smartcard::Gp::CapLoader
|
11
|
+
|
12
|
+
def setup
|
13
|
+
@cap_file = File.join(File.dirname(__FILE__), 'hello.cap')
|
14
|
+
@apdu_file = File.join(File.dirname(__FILE__), 'hello.apdu')
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_load_data
|
18
|
+
load_data = CapLoader.cap_load_data(@cap_file)
|
19
|
+
assert_equal File.read(@apdu_file),
|
20
|
+
load_data[:data].map { |ch| "%02x" % ch }.join(' ')
|
21
|
+
assert_equal [{:aid => [0x19, 0x83, 0x12, 0x29, 0x10, 0xDE, 0xAD],
|
22
|
+
:install_method => 8}], load_data[:applets]
|
23
|
+
end
|
24
|
+
end
|
data/test/gp/des_test.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Author:: Victor Costan
|
2
|
+
# Copyright:: Copyright (C) 2008 Massachusetts Institute of Technology
|
3
|
+
# License:: MIT
|
4
|
+
|
5
|
+
require 'smartcard'
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
|
9
|
+
class DesTest < Test::Unit::TestCase
|
10
|
+
Des = Smartcard::Gp::Des
|
11
|
+
|
12
|
+
def test_crypt
|
13
|
+
key = "@ABCDEFGHIJKLMNO"
|
14
|
+
data = "Quick brown fox "
|
15
|
+
iv = "0123456789ABCDEF"
|
16
|
+
golden = [0xC3, 0x21, 0xFE, 0x0D, 0xD1, 0x26, 0x34, 0xBE, 0xA6, 0x27, 0x7A,
|
17
|
+
0x00, 0x27, 0x26, 0xF0, 0xAA].pack('C*')
|
18
|
+
assert_equal golden, Des.crypt(key, data, iv)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_mac_3des
|
22
|
+
key = "@ABCDEFGHIJKLMNO"
|
23
|
+
data = "Quick brown fox "
|
24
|
+
golden = [0x99, 0xB8, 0x86, 0x86, 0x16, 0xBF, 0xDE, 0x01].pack('C*')
|
25
|
+
|
26
|
+
assert_equal golden, Des.mac_3des(key, data)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_mac_retail
|
30
|
+
data = [0x72, 0xC2, 0x9C, 0x23, 0x71, 0xCC, 0x9B, 0xDB, 0x65, 0xB7, 0x79,
|
31
|
+
0xB8, 0xE8, 0xD3, 0x7B, 0x29, 0xEC, 0xC1, 0x54, 0xAA, 0x56, 0xA8, 0x79,
|
32
|
+
0x9F, 0xAE, 0x2F, 0x49, 0x8F, 0x76, 0xED, 0x92, 0xF2].pack('C*')
|
33
|
+
key = [0x79, 0x62, 0xD9, 0xEC, 0xE0, 0x3D, 0x1A, 0xCD, 0x4C, 0x76, 0x08,
|
34
|
+
0x9D, 0xCE, 0x13, 0x15, 0x43].pack('C*')
|
35
|
+
golden = [0x5F, 0x14, 0x48, 0xEE, 0xA8, 0xAD, 0x90, 0xA7].pack('C*')
|
36
|
+
|
37
|
+
assert_equal golden, Des.mac_retail(key, data)
|
38
|
+
end
|
39
|
+
end
|
@@ -16,18 +16,207 @@ class GpCardMixinTest < Test::Unit::TestCase
|
|
16
16
|
# The sole purpose of this class is wrapping the mixin under test.
|
17
17
|
class MixinWrapper
|
18
18
|
include GpCardMixin
|
19
|
-
include Smartcard::Iso::IsoCardMixin
|
20
19
|
end
|
21
20
|
|
22
21
|
def setup
|
22
|
+
@file_aid = [0x19, 0x83, 0x12, 0x29, 0x10, 0xFA, 0xCE]
|
23
|
+
@app_aid = [0x19, 0x83, 0x12, 0x29, 0x10, 0xBA, 0xBE]
|
24
|
+
@host_auth = [0x00, 0x65, 0x07, 0x37, 0xD4, 0xB8, 0xDF, 0xDE, 0xD0, 0x7B,
|
25
|
+
0xAA, 0xA2, 0xDE, 0xDE, 0x82, 0x8B]
|
26
|
+
@host_challenge = [0x20, 0xBB, 0xE0, 0x4A, 0x1C, 0x6B, 0x6F, 0x50]
|
27
|
+
@file_data = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA,
|
28
|
+
0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x21, 0x32, 0x43, 0x54, 0x65,
|
29
|
+
0x76, 0x87, 0x98]
|
30
|
+
@max_apdu_length = 0x0F
|
31
|
+
end
|
32
|
+
|
33
|
+
def mock_card_manager_select(channel_mock)
|
34
|
+
flexmock(channel_mock).should_receive(:exchange_apdu).
|
35
|
+
with([0x00, 0xA4, 0x04, 0x00, 0x08, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00,
|
36
|
+
0x00, 0x00, 0x00]).
|
37
|
+
and_return([0x6F, 16, 0x84, 8, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
|
38
|
+
0x00, 0xA5, 4, 0x9F, 0x65, 1, 0x0F, 0x90, 0x00])
|
23
39
|
end
|
24
40
|
|
25
41
|
def test_select_application
|
26
42
|
mock = MixinWrapper.new
|
43
|
+
mock_card_manager_select mock
|
44
|
+
app_data = mock.select_application mock.gp_card_manager_aid
|
45
|
+
|
46
|
+
golden = { :aid => mock.gp_card_manager_aid, :max_apdu_length => 0x0F }
|
47
|
+
assert_equal golden, app_data
|
48
|
+
end
|
49
|
+
|
50
|
+
def mock_channel_setup(channel_mock)
|
51
|
+
flexmock(channel_mock).should_receive(:exchange_apdu).
|
52
|
+
with([0x80, 0x50, 0x00, 0x00, 0x08, 0x20, 0xBB, 0xE0, 0x4A, 0x1C, 0x6B,
|
53
|
+
0x6F, 0x50, 0x00]).
|
54
|
+
and_return([0x00, 0x00, 0x81, 0x29, 0x00, 0x76, 0x76, 0x91, 0x36, 0x54,
|
55
|
+
0xFF, 0x02, 0x00, 0x02, 0x59, 0x8D, 0xD3, 0x96, 0x1B, 0xFD,
|
56
|
+
0x04, 0xB5, 0xCF, 0x5A, 0xD0, 0x08, 0x3C, 0x01, 0x90, 0x00])
|
57
|
+
flexmock(Smartcard::Gp::Des).should_receive(:random_bytes).with(8).
|
58
|
+
and_return(@host_challenge.pack('C*'))
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_gp_setup_secure_channel
|
62
|
+
mock = MixinWrapper.new
|
63
|
+
mock_channel_setup mock
|
64
|
+
golden = {
|
65
|
+
:key_diversification => [0x00, 0x00, 0x81, 0x29, 0x00, 0x76, 0x76, 0x91,
|
66
|
+
0x36, 0x54],
|
67
|
+
:key_version => 0xFF, :protocol_id => 2, :counter => 2,
|
68
|
+
:challenge => [0x59, 0x8D, 0xD3, 0x96, 0x1B, 0xFD],
|
69
|
+
:auth => [0x04, 0xB5, 0xCF, 0x5A, 0xD0, 0x08, 0x3C, 0x01]
|
70
|
+
}
|
71
|
+
assert_equal golden, mock.gp_setup_secure_channel(@host_challenge)
|
72
|
+
end
|
73
|
+
|
74
|
+
def mock_channel_lock(channel_mock)
|
75
|
+
flexmock(channel_mock).should_receive(:exchange_apdu).
|
76
|
+
with([0x84, 0x82, 0x00, 0x00, 0x10, 0x00, 0x65, 0x07, 0x37, 0xD4, 0xB8,
|
77
|
+
0xDF, 0xDE, 0xD0, 0x7B, 0xAA, 0xA2, 0xDE, 0xDE, 0x82, 0x8B, 0x00]).
|
78
|
+
and_return([0x90, 0x00])
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_secure_channel
|
82
|
+
mock = MixinWrapper.new
|
83
|
+
mock_channel_setup mock
|
84
|
+
mock_channel_lock mock
|
85
|
+
|
86
|
+
mock.secure_channel
|
87
|
+
end
|
88
|
+
|
89
|
+
def mock_get_status_files_modules(channel_mock)
|
90
|
+
flexmock(channel_mock).should_receive(:exchange_apdu).
|
91
|
+
with([0x80, 0xF2, 0x10, 0x00, 0x02, 0x4F, 0x00, 0x00]).
|
92
|
+
and_return([0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x53, 0x50, 0x01, 0x00,
|
93
|
+
0x01, 0x08, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x53, 0x50, 0x41,
|
94
|
+
0x63, 0x10])
|
95
|
+
flexmock(channel_mock).should_receive(:exchange_apdu).
|
96
|
+
with([0x80, 0xF2, 0x10, 0x01, 0x02, 0x4F, 0x00, 0x00]).
|
97
|
+
and_return([0x07, 0x19, 0x83, 0x12, 0x29, 0x10, 0xFA, 0xCE, 0x01, 0x00,
|
98
|
+
0x01, 0x07, 0x19, 0x83, 0x12, 0x29, 0x10, 0xBA, 0xBE, 0x90,
|
99
|
+
0x00])
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_gp_get_status
|
103
|
+
mock = MixinWrapper.new
|
104
|
+
flexmock(mock).should_receive(:exchange_apdu).once.
|
105
|
+
with([0x80, 0xF2, 0x80, 0x00, 0x02, 0x4F, 0x00, 0x00]).
|
106
|
+
and_return([0x08, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01,
|
107
|
+
0x9E, 0x90, 0x00])
|
108
|
+
golden = [{ :lifecycle => :op_ready, :aid => [0xA0, 0, 0, 0, 3, 0, 0, 0],
|
109
|
+
:permissions => Set.new([:cvm_management, :card_reset, :card_terminate,
|
110
|
+
:card_lock, :security_domain]) }]
|
111
|
+
assert_equal golden, mock.gp_get_status(:issuer_sd),
|
112
|
+
'Issuer security domain'
|
113
|
+
|
114
|
+
mock = MixinWrapper.new
|
115
|
+
mock_get_status_files_modules mock
|
116
|
+
golden = [
|
117
|
+
{ :aid => [0xA0, 0x00, 0x00, 0x00, 0x03, 0x53, 0x50],
|
118
|
+
:permissions => Set.new, :lifecycle => :loaded,
|
119
|
+
:modules => [
|
120
|
+
{:aid => [0xA0, 0x00, 0x00, 0x00, 0x03, 0x53, 0x50, 0x41]}]},
|
121
|
+
{ :aid => [0x19, 0x83, 0x12, 0x29, 0x10, 0xFA, 0xCE],
|
122
|
+
:permissions => Set.new, :lifecycle => :loaded,
|
123
|
+
:modules => [{:aid => [0x19, 0x83, 0x12, 0x29, 0x10, 0xBA, 0xBE]}]},
|
124
|
+
]
|
125
|
+
|
126
|
+
assert_equal golden, mock.gp_get_status(:files_modules),
|
127
|
+
'Executable load files and modules'
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_gp_applications
|
131
|
+
mock = MixinWrapper.new
|
132
|
+
mock_card_manager_select mock
|
133
|
+
mock_channel_setup mock
|
134
|
+
mock_channel_lock mock
|
135
|
+
|
136
|
+
flexmock(mock).should_receive(:exchange_apdu).once.
|
137
|
+
with([0x80, 0xF2, 0x40, 0x00, 0x02, 0x4F, 0x00, 0x00]).
|
138
|
+
and_return([0x07, 0x19, 0x83, 0x12, 0x29, 0x10, 0xBA, 0xBE, 0x07, 0x00,
|
139
|
+
0x90, 0x00])
|
140
|
+
golden = [{ :aid => @app_aid,
|
141
|
+
:permissions => Set.new, :lifecycle => :selectable }]
|
142
|
+
assert_equal golden, mock.applications
|
143
|
+
end
|
144
|
+
|
145
|
+
def mock_delete_file(channel_mock)
|
146
|
+
flexmock(channel_mock).should_receive(:exchange_apdu).
|
147
|
+
with([0x80, 0xE4, 0x00, 0x80, 0x09, 0x4F, 0x07, 0x19, 0x83, 0x12, 0x29,
|
148
|
+
0x10, 0xFA, 0xCE, 0x00]).and_return([0x00, 0x90, 0x00])
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_gp_delete_file
|
152
|
+
mock = MixinWrapper.new
|
153
|
+
mock_delete_file mock
|
154
|
+
assert_equal [], mock.gp_delete_file(@file_aid)
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_delete_application
|
158
|
+
mock = MixinWrapper.new
|
159
|
+
mock_card_manager_select mock
|
160
|
+
mock_channel_setup mock
|
161
|
+
mock_channel_lock mock
|
162
|
+
mock_get_status_files_modules mock
|
163
|
+
mock_delete_file mock
|
164
|
+
|
165
|
+
assert mock.delete_application([0x19, 0x83, 0x12, 0x29, 0x10, 0xBA, 0xBE])
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_gp_install_load
|
169
|
+
mock = MixinWrapper.new
|
170
|
+
flexmock(mock).should_receive(:exchange_apdu).
|
171
|
+
with([0x80, 0xE6, 0x02, 0x00, 0x14, 0x07, 0x19, 0x83, 0x12, 0x29, 0x10,
|
172
|
+
0xFA, 0xCE, 0x08, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
173
|
+
0x00, 0x00, 0x00, 0x00]).and_return([0x00, 0x90, 0x00])
|
174
|
+
assert mock.gp_install_load(@file_aid, mock.gp_card_manager_aid)
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_gp_install_install
|
178
|
+
mock = MixinWrapper.new
|
179
|
+
flexmock(mock).should_receive(:exchange_apdu).
|
180
|
+
with([0x80, 0xE6, 0x0C, 0x00, 0x1E, 0x07, 0x19, 0x83, 0x12, 0x29, 0x10,
|
181
|
+
0xFA, 0xCE, 0x07, 0x19, 0x83, 0x12, 0x29, 0x10, 0xBA, 0xBE, 0x07,
|
182
|
+
0x19, 0x83, 0x12, 0x29, 0x10, 0xBA, 0xBE, 0x01, 0x80, 0x02, 0xC9,
|
183
|
+
0x00, 0x00, 0x00]).and_return([0x00, 0x90, 0x00])
|
184
|
+
assert mock.gp_install_selectable(@file_aid, @app_aid, @app_aid,
|
185
|
+
[:security_domain])
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_gp_load_file
|
189
|
+
mock = MixinWrapper.new
|
190
|
+
flexmock(mock).should_receive(:exchange_apdu).
|
191
|
+
with([0x80, 0xE8, 0x00, 0x00, 0x0A, 0xC4, 0x17, 0x11, 0x22, 0x33, 0x44,
|
192
|
+
0x55, 0x66, 0x77, 0x88, 0x00]).and_return([0x00, 0x90, 0x00])
|
27
193
|
flexmock(mock).should_receive(:exchange_apdu).
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
194
|
+
with([0x80, 0xE8, 0x00, 0x01, 0x0A, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE,
|
195
|
+
0xFF, 0x21, 0x32, 0x43, 0x00]).and_return([0x00, 0x90, 0x00])
|
196
|
+
flexmock(mock).should_receive(:exchange_apdu).
|
197
|
+
with([0x80, 0xE8, 0x80, 0x02, 0x05, 0x54, 0x65, 0x76, 0x87, 0x98, 0x00]).
|
198
|
+
and_return([0x00, 0x90, 0x00])
|
199
|
+
assert mock.gp_load_file @file_data, @max_apdu_length
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_install_applet_live
|
203
|
+
# Establish transport to live card.
|
204
|
+
transport = Smartcard::Iso.auto_transport
|
205
|
+
class <<transport
|
206
|
+
include GpCardMixin
|
207
|
+
end
|
208
|
+
|
209
|
+
# Install applet.
|
210
|
+
applet_aid = [0x19, 0x83, 0x12, 0x29, 0x10, 0xDE, 0xAD]
|
211
|
+
cap_file = File.join File.dirname(__FILE__), 'hello.cap'
|
212
|
+
transport.install_applet cap_file,
|
213
|
+
[0x19, 0x83, 0x12, 0x29, 0x10, 0xDE, 0xAE]
|
214
|
+
|
215
|
+
# Ensure applet works.
|
216
|
+
transport.select_application applet_aid
|
217
|
+
assert_equal "Hello!", transport.iso_apdu!(:ins => 0x00).pack('C*')
|
218
|
+
|
219
|
+
# Uninstall applet.
|
220
|
+
transport.delete_application applet_aid
|
32
221
|
end
|
33
222
|
end
|
data/test/gp/hello.apdu
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
01 00 11 de ca ff ed 01 02 04 00 01 07 19 83 12 29 10 de ae 02 00 1f 00 11 00 1f 00 0b 00 0b 00 2a 00 0c 00 52 00 13 00 0e 00 00 00 63 00 02 00 01 00 06 01 01 00 04 00 0b 01 00 01 07 a0 00 00 00 62 01 01 03 00 0b 01 07 19 83 12 29 10 de ad 00 08 06 00 0c 00 80 03 00 ff 00 07 01 00 00 00 1c 07 00 52 00 01 10 18 8c 00 01 7a 05 30 8f 00 04 3d 8c 00 08 18 1d 04 41 18 1d 25 8b 00 05 7a 05 21 18 8b 00 03 60 03 7a 19 8b 00 09 2d 1a 04 25 73 00 1e 00 00 00 00 00 09 7b 00 00 03 1a 03 10 06 8d 00 07 3b 19 03 10 06 8b 00 06 70 08 11 6d 00 8d 00 02 7a 08 00 13 00 02 00 01 00 01 03 00 06 48 65 6c 6c 6f 21 00 00 00 00 05 00 2a 00 0a 05 00 00 00 06 80 03 00 06 80 07 01 03 80 03 03 01 00 00 00 03 80 03 02 03 80 0a 08 06 80 10 01 06 00 00 01 03 80 0a 01 09 00 0e 00 00 00 0a 05 06 04 0a 07 07 10 08 08 08
|
data/test/gp/hello.cap
ADDED
Binary file
|
@@ -24,20 +24,21 @@ class IsoCardMixinTest < Test::Unit::TestCase
|
|
24
24
|
def test_serialize_apdu
|
25
25
|
s = lambda { |apdu| IsoCardMixin.serialize_apdu apdu }
|
26
26
|
|
27
|
-
assert_equal [0x00, 0x05, 0x00, 0x00, 0x00], s[:ins => 0x05],
|
27
|
+
assert_equal [0x00, 0x05, 0x00, 0x00, 0x00, 0x00], s[:ins => 0x05],
|
28
28
|
'Specified INS'
|
29
|
-
assert_equal [0x00, 0x09, 0x00, 0x01, 0x00
|
29
|
+
assert_equal [0x00, 0x09, 0x00, 0x01, 0x00, 0x00],
|
30
|
+
s[:ins => 0x09, :p2 => 0x01],
|
30
31
|
'Specified INS and P2'
|
31
|
-
assert_equal [0x00, 0xF9, 0xAC, 0xEF, 0x00],
|
32
|
+
assert_equal [0x00, 0xF9, 0xAC, 0xEF, 0x00, 0x00],
|
32
33
|
s[:ins => 0xF9, :p1 => 0xAC, :p2 => 0xEF],
|
33
34
|
'Specified INS, P1, P2'
|
34
|
-
assert_equal [0x00, 0xFA, 0xAD, 0xEC, 0x00],
|
35
|
+
assert_equal [0x00, 0xFA, 0xAD, 0xEC, 0x00, 0x00],
|
35
36
|
s[:ins => 0xFA, :p12 => [0xAD, 0xEC]],
|
36
37
|
'Specified INS, P1+P2'
|
37
|
-
assert_equal [0x00, 0x0E, 0x00, 0x00, 0x04, 0x33, 0x95, 0x81, 0x63],
|
38
|
+
assert_equal [0x00, 0x0E, 0x00, 0x00, 0x04, 0x33, 0x95, 0x81, 0x63, 0x00],
|
38
39
|
s[:ins => 0x0E, :data => [0x33, 0x95, 0x81, 0x63]],
|
39
40
|
'Specified INS and DATA'
|
40
|
-
assert_equal [0x80, 0x0F, 0xBA, 0xBE, 0x03, 0x31, 0x41, 0x59],
|
41
|
+
assert_equal [0x80, 0x0F, 0xBA, 0xBE, 0x03, 0x31, 0x41, 0x59, 0x00],
|
41
42
|
s[:cla => 0x80, :ins => 0x0F, :p1 => 0xBA, :p2 => 0xBE,
|
42
43
|
:data => [0x31, 0x41, 0x59]],
|
43
44
|
'Specified everything'
|
@@ -60,7 +61,7 @@ class IsoCardMixinTest < Test::Unit::TestCase
|
|
60
61
|
def win_mock
|
61
62
|
mock = MixinWrapper.new
|
62
63
|
flexmock(mock).should_receive(:exchange_apdu).
|
63
|
-
with([0x00, 0xF9, 0xAC, 0x00, 0x02, 0x31, 0x41]).
|
64
|
+
with([0x00, 0xF9, 0xAC, 0x00, 0x02, 0x31, 0x41, 0x00]).
|
64
65
|
and_return([0x67, 0x31, 0x90, 0x00])
|
65
66
|
mock
|
66
67
|
end
|
@@ -71,7 +72,7 @@ class IsoCardMixinTest < Test::Unit::TestCase
|
|
71
72
|
def lose_mock
|
72
73
|
mock = MixinWrapper.new
|
73
74
|
flexmock(mock).should_receive(:exchange_apdu).
|
74
|
-
with([0x00, 0xF9, 0xAC, 0x00, 0x02, 0x31, 0x41]).
|
75
|
+
with([0x00, 0xF9, 0xAC, 0x00, 0x02, 0x31, 0x41, 0x00]).
|
75
76
|
and_return([0x86, 0x31])
|
76
77
|
mock
|
77
78
|
end
|
@@ -34,6 +34,9 @@ class JcopRemoteTest < Test::Unit::TestCase
|
|
34
34
|
@received << apdu
|
35
35
|
@responses.shift
|
36
36
|
end
|
37
|
+
def card_atr
|
38
|
+
[0x31, 0x41, 0x59].pack('C*')
|
39
|
+
end
|
37
40
|
end
|
38
41
|
|
39
42
|
def setup
|
@@ -88,7 +91,7 @@ class JcopRemoteTest < Test::Unit::TestCase
|
|
88
91
|
end
|
89
92
|
|
90
93
|
def test_iso_card_integration
|
91
|
-
apdu_request = [0x00, 0x31, 0x41, 0x59, 0x00]
|
94
|
+
apdu_request = [0x00, 0x31, 0x41, 0x59, 0x00, 0x00]
|
92
95
|
apdu_response = [0x27, 0x90, 0x00]
|
93
96
|
|
94
97
|
logic = Logic.new([apdu_response])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smartcard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: x86-mswin32-60
|
6
6
|
authors:
|
7
7
|
- Victor Costan
|
@@ -9,10 +9,19 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-11-01 01:00:00 -04:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rubyzip
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.9.1
|
24
|
+
version:
|
16
25
|
description: Interface with ISO 7816 smart cards.
|
17
26
|
email: victor@costan.us
|
18
27
|
executables: []
|
@@ -22,6 +31,8 @@ extensions: []
|
|
22
31
|
extra_rdoc_files:
|
23
32
|
- BUILD
|
24
33
|
- CHANGELOG
|
34
|
+
- LICENSE
|
35
|
+
- README
|
25
36
|
- ext/smartcard_pcsc/extconf.rb
|
26
37
|
- ext/smartcard_pcsc/pcsc.h
|
27
38
|
- ext/smartcard_pcsc/pcsc_card.c
|
@@ -35,6 +46,10 @@ extra_rdoc_files:
|
|
35
46
|
- ext/smartcard_pcsc/pcsc_reader_states.c
|
36
47
|
- ext/smartcard_pcsc/pcsc_surrogate_reader.h
|
37
48
|
- ext/smartcard_pcsc/pcsc_surrogate_wintypes.h
|
49
|
+
- lib/smartcard.rb
|
50
|
+
- lib/smartcard/gp/asn1_ber.rb
|
51
|
+
- lib/smartcard/gp/cap_loader.rb
|
52
|
+
- lib/smartcard/gp/des.rb
|
38
53
|
- lib/smartcard/gp/gp_card_mixin.rb
|
39
54
|
- lib/smartcard/iso/auto_configurator.rb
|
40
55
|
- lib/smartcard/iso/iso_card_mixin.rb
|
@@ -44,12 +59,13 @@ extra_rdoc_files:
|
|
44
59
|
- lib/smartcard/iso/pcsc_transport.rb
|
45
60
|
- lib/smartcard/iso/transport.rb
|
46
61
|
- lib/smartcard/pcsc/pcsc_exception.rb
|
47
|
-
- lib/smartcard.rb
|
48
|
-
- LICENSE
|
49
|
-
- README
|
50
62
|
files:
|
51
63
|
- BUILD
|
52
64
|
- CHANGELOG
|
65
|
+
- LICENSE
|
66
|
+
- Manifest
|
67
|
+
- README
|
68
|
+
- Rakefile
|
53
69
|
- ext/smartcard_pcsc/extconf.rb
|
54
70
|
- ext/smartcard_pcsc/pcsc.h
|
55
71
|
- ext/smartcard_pcsc/pcsc_card.c
|
@@ -63,6 +79,10 @@ files:
|
|
63
79
|
- ext/smartcard_pcsc/pcsc_reader_states.c
|
64
80
|
- ext/smartcard_pcsc/pcsc_surrogate_reader.h
|
65
81
|
- ext/smartcard_pcsc/pcsc_surrogate_wintypes.h
|
82
|
+
- lib/smartcard.rb
|
83
|
+
- lib/smartcard/gp/asn1_ber.rb
|
84
|
+
- lib/smartcard/gp/cap_loader.rb
|
85
|
+
- lib/smartcard/gp/des.rb
|
66
86
|
- lib/smartcard/gp/gp_card_mixin.rb
|
67
87
|
- lib/smartcard/iso/auto_configurator.rb
|
68
88
|
- lib/smartcard/iso/iso_card_mixin.rb
|
@@ -72,19 +92,19 @@ files:
|
|
72
92
|
- lib/smartcard/iso/pcsc_transport.rb
|
73
93
|
- lib/smartcard/iso/transport.rb
|
74
94
|
- lib/smartcard/pcsc/pcsc_exception.rb
|
75
|
-
-
|
76
|
-
-
|
77
|
-
-
|
78
|
-
- Rakefile
|
79
|
-
- README
|
80
|
-
- smartcard.gemspec
|
95
|
+
- test/gp/asn1_ber_test.rb
|
96
|
+
- test/gp/cap_loader_test.rb
|
97
|
+
- test/gp/des_test.rb
|
81
98
|
- test/gp/gp_card_mixin_test.rb
|
99
|
+
- test/gp/hello.apdu
|
100
|
+
- test/gp/hello.cap
|
82
101
|
- test/iso/auto_configurator_test.rb
|
83
102
|
- test/iso/iso_card_mixin_test.rb
|
84
103
|
- test/iso/jcop_remote_test.rb
|
85
104
|
- test/pcsc/containers_test.rb
|
86
105
|
- test/pcsc/smoke_test.rb
|
87
106
|
- tests/ts_pcsc_ext.rb
|
107
|
+
- smartcard.gemspec
|
88
108
|
- lib/smartcard/pcsc.so
|
89
109
|
has_rdoc: true
|
90
110
|
homepage: http://www.costan.us/smartcard
|
@@ -121,6 +141,9 @@ signing_key:
|
|
121
141
|
specification_version: 3
|
122
142
|
summary: Interface with ISO 7816 smart cards.
|
123
143
|
test_files:
|
144
|
+
- test/gp/asn1_ber_test.rb
|
145
|
+
- test/gp/cap_loader_test.rb
|
146
|
+
- test/gp/des_test.rb
|
124
147
|
- test/gp/gp_card_mixin_test.rb
|
125
148
|
- test/iso/auto_configurator_test.rb
|
126
149
|
- test/iso/iso_card_mixin_test.rb
|