smartcard 0.4.11 → 0.5.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 +2 -0
- data/Manifest +11 -16
- data/Rakefile +9 -16
- data/lib/smartcard.rb +11 -2
- data/lib/smartcard/iso/pcsc_transport.rb +22 -37
- data/lib/smartcard/pcsc/card.rb +281 -0
- data/lib/smartcard/pcsc/context.rb +160 -0
- data/lib/smartcard/pcsc/ffi_autogen.rb +327 -0
- data/lib/smartcard/pcsc/ffi_functions.rb +50 -0
- data/lib/smartcard/pcsc/ffi_lib.rb +38 -0
- data/lib/smartcard/pcsc/ffi_structs.rb +57 -0
- data/lib/smartcard/pcsc/pcsc_exception.rb +8 -3
- data/lib/smartcard/pcsc/reader_state_queries.rb +167 -0
- data/smartcard.gemspec +9 -7
- data/tasks/ffi_codegen.rb +145 -0
- data/test/pcsc/card_test.rb +68 -0
- data/test/pcsc/context_test.rb +64 -0
- data/test/pcsc/reader_state_queries_test.rb +72 -0
- metadata +42 -42
- data/ext/smartcard_pcsc/extconf.rb +0 -79
- data/ext/smartcard_pcsc/pcsc.h +0 -52
- data/ext/smartcard_pcsc/pcsc_card.c +0 -492
- data/ext/smartcard_pcsc/pcsc_constants.c +0 -195
- data/ext/smartcard_pcsc/pcsc_context.c +0 -290
- data/ext/smartcard_pcsc/pcsc_exception.c +0 -39
- data/ext/smartcard_pcsc/pcsc_io_request.c +0 -129
- data/ext/smartcard_pcsc/pcsc_main.c +0 -11
- data/ext/smartcard_pcsc/pcsc_multi_strings.c +0 -70
- data/ext/smartcard_pcsc/pcsc_namespace.c +0 -18
- data/ext/smartcard_pcsc/pcsc_reader_states.c +0 -331
- data/ext/smartcard_pcsc/pcsc_surrogate_reader.h +0 -207
- data/ext/smartcard_pcsc/pcsc_surrogate_wintypes.h +0 -63
- data/test/pcsc/containers_test.rb +0 -59
- data/test/pcsc/smoke_test.rb +0 -28
- data/tests/ts_pcsc_ext.rb +0 -76
@@ -0,0 +1,50 @@
|
|
1
|
+
# Function declarations for the PC/SC FFI.
|
2
|
+
#
|
3
|
+
# Author:: Victor Costan
|
4
|
+
# Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'ffi'
|
8
|
+
|
9
|
+
# :nodoc: namespace
|
10
|
+
module Smartcard::PCSC
|
11
|
+
|
12
|
+
|
13
|
+
# FFI to the native PC/SC libraries.
|
14
|
+
module FFILib
|
15
|
+
str_suffix = FFI::Platform.windows? ? 'A' : ''
|
16
|
+
attach_function :establish_context, 'SCardEstablishContext',
|
17
|
+
[Scope, :pointer, :pointer, :pointer], Status
|
18
|
+
attach_function :release_context, 'SCardReleaseContext', [Word], Status
|
19
|
+
attach_function :is_valid_context, 'SCardIsValidContext', [Word], Status
|
20
|
+
attach_function :list_reader_groups, 'SCardListReaderGroups' + str_suffix,
|
21
|
+
[Word, :pointer, :pointer], Status
|
22
|
+
attach_function :list_readers, 'SCardListReaders' + str_suffix,
|
23
|
+
[Word, :pointer, :pointer, :pointer], Status
|
24
|
+
attach_function :get_status_change, 'SCardGetStatusChange' + str_suffix,
|
25
|
+
[Word, Word, :pointer, Word], Status
|
26
|
+
|
27
|
+
attach_function :card_connect, 'SCardConnect' + str_suffix,
|
28
|
+
[Word, :string, Share, Protocol, :pointer, :pointer], Status
|
29
|
+
attach_function :card_reconnect, 'SCardReconnect',
|
30
|
+
[Word, Share, Protocol, Disposition, :pointer], Status
|
31
|
+
attach_function :card_disconnect, 'SCardDisconnect',
|
32
|
+
[Word, Disposition], Status
|
33
|
+
attach_function :begin_transaction, 'SCardBeginTransaction', [Word], Status
|
34
|
+
attach_function :end_transaction, 'SCardEndTransaction',
|
35
|
+
[Word, Disposition], Status
|
36
|
+
attach_function :get_attrib, 'SCardGetAttrib',
|
37
|
+
[Word, Attribute, :pointer, :pointer], Status
|
38
|
+
attach_function :set_attrib, 'SCardSetAttrib',
|
39
|
+
[Word, Attribute, :pointer, Word], Status
|
40
|
+
attach_function :transmit, 'SCardTransmit',
|
41
|
+
[Word, IoRequest, :pointer, Word, IoRequest, :pointer,
|
42
|
+
:pointer], Status
|
43
|
+
attach_function :card_control, 'SCardControl',
|
44
|
+
[Word, Word, :pointer, Word, :pointer, Word, :pointer], Status
|
45
|
+
attach_function :card_status, 'SCardStatus' + str_suffix,
|
46
|
+
[Word, :pointer, :pointer, :pointer, :pointer, :pointer,
|
47
|
+
:pointer], Status
|
48
|
+
end # module Smartcard::PCSC::FFILib
|
49
|
+
|
50
|
+
end # namespace Smartcard::PCSC
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Declaration for the module enclosing the PC/SC FFI hooks.
|
2
|
+
#
|
3
|
+
# Author:: Victor Costan
|
4
|
+
# Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'ffi'
|
8
|
+
|
9
|
+
# :nodoc: namespace
|
10
|
+
module Smartcard::PCSC
|
11
|
+
|
12
|
+
|
13
|
+
# FFI to the native PC/SC libraries.
|
14
|
+
module FFILib
|
15
|
+
extend FFI::Library
|
16
|
+
# NOTE: the information is hacked together from the PCSClite headers reader.h,
|
17
|
+
# winscard.h, and pcsclite.h, available in /usr/include/PCSC
|
18
|
+
|
19
|
+
if FFI::Platform.windows?
|
20
|
+
ffi_lib 'winscard'
|
21
|
+
elsif FFI::Platform.mac?
|
22
|
+
ffi_lib '/System/Library/Frameworks/PCSC.framework/PCSC'
|
23
|
+
else
|
24
|
+
ffi_lib 'pcsclite'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end # namespace Smartcard::PCSC
|
29
|
+
|
30
|
+
# Add Fixnum#ord to Ruby 1.8.6's Fixnum, if it's not already there.
|
31
|
+
unless 0.respond_to?(:ord) or '0'.respond_to?(:ord)
|
32
|
+
# :nodoc: all
|
33
|
+
class Fixnum
|
34
|
+
def ord
|
35
|
+
self
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Function declarations for the PC/SC FFI.
|
2
|
+
#
|
3
|
+
# Author:: Victor Costan
|
4
|
+
# Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'ffi'
|
8
|
+
|
9
|
+
# :nodoc: namespace
|
10
|
+
module Smartcard::PCSC
|
11
|
+
|
12
|
+
|
13
|
+
# FFI to the native PC/SC libraries.
|
14
|
+
module FFILib
|
15
|
+
if FFI::Platform.mac?
|
16
|
+
# 64-bit MacOS is different from 64-bit Linux.
|
17
|
+
Word = :uint32
|
18
|
+
else
|
19
|
+
Word = :ulong
|
20
|
+
end
|
21
|
+
|
22
|
+
# Used to synthesize pointers to unsigned integers.
|
23
|
+
class WordPtr < FFI::Struct
|
24
|
+
# NOTE: this hack is necessary because FFI::Pointer can only read signed
|
25
|
+
# values right now (FFI 0.5.3).
|
26
|
+
layout :value, Word
|
27
|
+
end
|
28
|
+
|
29
|
+
# Used to obtain information and state changes about all PC/SC readers.
|
30
|
+
class ReaderStateQuery < FFI::Struct
|
31
|
+
layout :reader_name, :pointer,
|
32
|
+
:user_data, :pointer,
|
33
|
+
:current_state, Word,
|
34
|
+
:event_state, Word,
|
35
|
+
:atr_length, Word,
|
36
|
+
:atr, [:char, Consts::MAX_ATR_SIZE]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Low-level protocol information for APDU transmission and reception.
|
40
|
+
class IoRequest < FFI::Struct
|
41
|
+
layout :protocol, Word,
|
42
|
+
:pci_length, Word
|
43
|
+
end
|
44
|
+
|
45
|
+
# Global variables for IoRequests for protocols T=0, T=1, and RAW.
|
46
|
+
begin
|
47
|
+
PCI_T0 = attach_variable :pci_t0, 'g_rgSCardT0Pci', IoRequest
|
48
|
+
PCI_T1 = attach_variable :pci_t1, 'g_rgSCardT1Pci', IoRequest
|
49
|
+
PCI_RAW = attach_variable :pci_raw, 'g_rgSCardRawPci', IoRequest
|
50
|
+
rescue
|
51
|
+
# Couldn't find the global variables, so we must be on Windows.
|
52
|
+
|
53
|
+
# TODO(costan): figure out the names of the Windows global variables
|
54
|
+
end
|
55
|
+
end # module Smartcard::PCSC::FFILib
|
56
|
+
|
57
|
+
end # namespace Smartcard::PCSC
|
@@ -1,5 +1,10 @@
|
|
1
1
|
# Contains information about an exception at the PC/SC layer.
|
2
|
-
class Smartcard::PCSC::Exception
|
3
|
-
|
4
|
-
|
2
|
+
class Smartcard::PCSC::Exception < RuntimeError
|
3
|
+
def initialize(error_status)
|
4
|
+
@pcsc_status = error_status
|
5
|
+
super error_status.to_s
|
6
|
+
end
|
7
|
+
|
8
|
+
# The PC/SC error status that caused this error.
|
9
|
+
attr_reader :pcsc_status
|
5
10
|
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# Connects Ruby to the PC/SC resource manager (wraps SCARDCONTEXT).
|
2
|
+
#
|
3
|
+
# Author:: Victor Costan
|
4
|
+
# Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'set'
|
8
|
+
|
9
|
+
# :nodoc: namespace
|
10
|
+
module Smartcard::PCSC
|
11
|
+
|
12
|
+
|
13
|
+
# A continuous array of reader state queries.
|
14
|
+
class ReaderStateQueries
|
15
|
+
# Creates an array of reader state queries.
|
16
|
+
#
|
17
|
+
# The states are unusable until they are assigned reader names by calling
|
18
|
+
# set_reader_name_of.
|
19
|
+
def initialize(num_states)
|
20
|
+
@_buffer = FFI::MemoryPointer.new :char,
|
21
|
+
FFILib::ReaderStateQuery.size * num_states
|
22
|
+
@queries = (0...num_states).map do |i|
|
23
|
+
FFILib::ReaderStateQuery.new @_buffer + FFILib::ReaderStateQuery.size * i
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# A query in the array.
|
28
|
+
def [](index)
|
29
|
+
raise TypeError unless index.kind_of? Numeric
|
30
|
+
raise IndexError if index >= @queries.length
|
31
|
+
@queries[index]
|
32
|
+
end
|
33
|
+
|
34
|
+
# The number of queries in the array.
|
35
|
+
def length
|
36
|
+
@queries.length
|
37
|
+
end
|
38
|
+
|
39
|
+
# Updates all the queries to acknowledge status changes.
|
40
|
+
#
|
41
|
+
# This is a convenience method intended to be called after
|
42
|
+
# Smartcard::PCSC::Context#wait_for_status_change.
|
43
|
+
def ack_changes
|
44
|
+
@queries.each { |query| query.current_state = query.event_state }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Called by FFI::AutoPointer to release the reader states array.
|
48
|
+
#
|
49
|
+
# This should not be called by client code.
|
50
|
+
def self._release_states(pointer)
|
51
|
+
pointer.free
|
52
|
+
end
|
53
|
+
|
54
|
+
# The low-level _SCARD_READERSTATE_ data.
|
55
|
+
#
|
56
|
+
# This should not be used by client code.
|
57
|
+
attr_reader :_buffer
|
58
|
+
end # class Smartcard::PCSC::ReaderStates
|
59
|
+
|
60
|
+
|
61
|
+
# :nodoc: extends the reader states with nice accessors
|
62
|
+
class FFILib::ReaderStateQuery
|
63
|
+
# The query's current state.
|
64
|
+
#
|
65
|
+
# Smartcard::PCSC::Context#wait_for_status_change blocks while the reader
|
66
|
+
# state equals this.
|
67
|
+
#
|
68
|
+
# The value is a Set whose elements are FFILib::CardState members.
|
69
|
+
def current_state
|
70
|
+
FFILib::ReaderStateQuery.unpack_state self[:current_state]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Changes the query's current state.
|
74
|
+
#
|
75
|
+
# Smartcard::PCSC::Context#wait_for_status_change blocks while the reader
|
76
|
+
# state equals this.
|
77
|
+
#
|
78
|
+
# The new value can be a symbol in FFILib::CardState, or an Enumerable
|
79
|
+
# containing such symbols.
|
80
|
+
def current_state=(new_state)
|
81
|
+
self[:current_state] = FFILib::ReaderStateQuery.pack_state new_state
|
82
|
+
end
|
83
|
+
|
84
|
+
# The query's event state.
|
85
|
+
#
|
86
|
+
# Smartcard::PCSC::Context#wait_for_status_change updates this value before it
|
87
|
+
# returns.
|
88
|
+
#
|
89
|
+
# The value is a Set whose elements are FFILib::CardState members.
|
90
|
+
def event_state
|
91
|
+
FFILib::ReaderStateQuery.unpack_state self[:event_state]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Changes the query's event state.
|
95
|
+
#
|
96
|
+
# Smartcard::PCSC::Context#wait_for_status_change updates this value before it
|
97
|
+
# returns.
|
98
|
+
#
|
99
|
+
# The new value can be a symbol in FFILib::CardState, or an Enumerable
|
100
|
+
# containing such symbols.
|
101
|
+
def event_state=(new_state)
|
102
|
+
self[:event_state] = FFILib::ReaderStateQuery.pack_state new_state
|
103
|
+
end
|
104
|
+
|
105
|
+
# The ATR of the smart-card in the query's reader.
|
106
|
+
#
|
107
|
+
# Smartcard::PCSC::Context#wait_for_status_change updates this value before it
|
108
|
+
# returns.
|
109
|
+
#
|
110
|
+
# The value is a string containing the ATR bytes.
|
111
|
+
def atr
|
112
|
+
self[:atr].to_ptr.get_bytes 0, self[:atr_length]
|
113
|
+
end
|
114
|
+
|
115
|
+
# Changes the smart-card ATR stored in the query.
|
116
|
+
#
|
117
|
+
# Smartcard::PCSC::Context#wait_for_status_change updates this value before it
|
118
|
+
# returns.
|
119
|
+
#
|
120
|
+
# The new value should be a string containing the ATR bytes.
|
121
|
+
def atr=(new_atr)
|
122
|
+
if new_atr.length > max_length = FFILib::Consts::MAX_ATR_SIZE
|
123
|
+
raise ArgumentError, "ATR above maximum length of #{max_length}"
|
124
|
+
end
|
125
|
+
|
126
|
+
self[:atr_length] = new_atr.length
|
127
|
+
self[:atr].to_ptr.put_bytes 0, new_atr, 0, new_atr.length
|
128
|
+
end
|
129
|
+
|
130
|
+
# The name of the reader referenceed by this query.
|
131
|
+
#
|
132
|
+
# Smartcard::PCSC::Context#wait_for_status_change never changes this value.
|
133
|
+
def reader_name
|
134
|
+
self[:reader_name].read_string
|
135
|
+
end
|
136
|
+
|
137
|
+
# Changes the name of the reader referenceed by this query.
|
138
|
+
#
|
139
|
+
# Smartcard::PCSC::Context#wait_for_status_change never changes this value.
|
140
|
+
def reader_name=(new_name)
|
141
|
+
self[:reader_name].free if self[:reader_name].kind_of? FFI::MemoryPointer
|
142
|
+
self[:reader_name] = FFI::MemoryPointer.from_string new_name
|
143
|
+
end
|
144
|
+
|
145
|
+
# Packs an unpacked card state (symbol or set of symbols) into a number.
|
146
|
+
#
|
147
|
+
# This should not be used by client code.
|
148
|
+
def self.pack_state(unpacked_state)
|
149
|
+
if unpacked_state.kind_of? Enumerable
|
150
|
+
state = 0
|
151
|
+
unpacked_state.each { |bit| state |= FFILib::CardState[bit] }
|
152
|
+
return state
|
153
|
+
end
|
154
|
+
FFILib::CardState[unpacked_state]
|
155
|
+
end
|
156
|
+
|
157
|
+
# Unpacks a numeric card state into a Set of symbols.
|
158
|
+
def self.unpack_state(packed_state)
|
159
|
+
state = Set.new
|
160
|
+
FFILib::CardState.to_h.each do |bit, mask|
|
161
|
+
state << bit if (packed_state & mask) == mask and mask != 0
|
162
|
+
end
|
163
|
+
state
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end # namespace Smartcard::PCSC
|
data/smartcard.gemspec
CHANGED
@@ -2,40 +2,42 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{smartcard}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.5.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Victor Costan"]
|
9
|
-
s.date = %q{2009-11-
|
9
|
+
s.date = %q{2009-11-27}
|
10
10
|
s.description = %q{Interface with ISO 7816 smart cards.}
|
11
11
|
s.email = %q{victor@costan.us}
|
12
|
-
s.
|
13
|
-
s.
|
14
|
-
s.files = ["BUILD", "CHANGELOG", "LICENSE", "Manifest", "README", "Rakefile", "ext/smartcard_pcsc/extconf.rb", "ext/smartcard_pcsc/pcsc.h", "ext/smartcard_pcsc/pcsc_card.c", "ext/smartcard_pcsc/pcsc_constants.c", "ext/smartcard_pcsc/pcsc_context.c", "ext/smartcard_pcsc/pcsc_exception.c", "ext/smartcard_pcsc/pcsc_io_request.c", "ext/smartcard_pcsc/pcsc_main.c", "ext/smartcard_pcsc/pcsc_multi_strings.c", "ext/smartcard_pcsc/pcsc_namespace.c", "ext/smartcard_pcsc/pcsc_reader_states.c", "ext/smartcard_pcsc/pcsc_surrogate_reader.h", "ext/smartcard_pcsc/pcsc_surrogate_wintypes.h", "lib/smartcard.rb", "lib/smartcard/gp/asn1_ber.rb", "lib/smartcard/gp/cap_loader.rb", "lib/smartcard/gp/des.rb", "lib/smartcard/gp/gp_card_mixin.rb", "lib/smartcard/iso/apdu_error.rb", "lib/smartcard/iso/auto_configurator.rb", "lib/smartcard/iso/iso_card_mixin.rb", "lib/smartcard/iso/jcop_remote_protocol.rb", "lib/smartcard/iso/jcop_remote_server.rb", "lib/smartcard/iso/jcop_remote_transport.rb", "lib/smartcard/iso/pcsc_transport.rb", "lib/smartcard/iso/transport.rb", "lib/smartcard/pcsc/pcsc_exception.rb", "test/gp/asn1_ber_test.rb", "test/gp/cap_loader_test.rb", "test/gp/des_test.rb", "test/gp/gp_card_mixin_compat_test.rb", "test/gp/gp_card_mixin_test.rb", "test/gp/hello.apdu", "test/gp/hello.cap", "test/iso/auto_configurator_test.rb", "test/iso/iso_card_mixin_test.rb", "test/iso/iso_exception_test.rb", "test/iso/jcop_remote_test.rb", "test/pcsc/containers_test.rb", "test/pcsc/smoke_test.rb", "tests/ts_pcsc_ext.rb", "smartcard.gemspec"]
|
12
|
+
s.extra_rdoc_files = ["BUILD", "CHANGELOG", "LICENSE", "README", "lib/smartcard.rb", "lib/smartcard/gp/asn1_ber.rb", "lib/smartcard/gp/cap_loader.rb", "lib/smartcard/gp/des.rb", "lib/smartcard/gp/gp_card_mixin.rb", "lib/smartcard/iso/apdu_error.rb", "lib/smartcard/iso/auto_configurator.rb", "lib/smartcard/iso/iso_card_mixin.rb", "lib/smartcard/iso/jcop_remote_protocol.rb", "lib/smartcard/iso/jcop_remote_server.rb", "lib/smartcard/iso/jcop_remote_transport.rb", "lib/smartcard/iso/pcsc_transport.rb", "lib/smartcard/iso/transport.rb", "lib/smartcard/pcsc/card.rb", "lib/smartcard/pcsc/context.rb", "lib/smartcard/pcsc/ffi_autogen.rb", "lib/smartcard/pcsc/ffi_functions.rb", "lib/smartcard/pcsc/ffi_lib.rb", "lib/smartcard/pcsc/ffi_structs.rb", "lib/smartcard/pcsc/pcsc_exception.rb", "lib/smartcard/pcsc/reader_state_queries.rb", "tasks/ffi_codegen.rb"]
|
13
|
+
s.files = ["BUILD", "CHANGELOG", "LICENSE", "Manifest", "README", "Rakefile", "lib/smartcard.rb", "lib/smartcard/gp/asn1_ber.rb", "lib/smartcard/gp/cap_loader.rb", "lib/smartcard/gp/des.rb", "lib/smartcard/gp/gp_card_mixin.rb", "lib/smartcard/iso/apdu_error.rb", "lib/smartcard/iso/auto_configurator.rb", "lib/smartcard/iso/iso_card_mixin.rb", "lib/smartcard/iso/jcop_remote_protocol.rb", "lib/smartcard/iso/jcop_remote_server.rb", "lib/smartcard/iso/jcop_remote_transport.rb", "lib/smartcard/iso/pcsc_transport.rb", "lib/smartcard/iso/transport.rb", "lib/smartcard/pcsc/card.rb", "lib/smartcard/pcsc/context.rb", "lib/smartcard/pcsc/ffi_autogen.rb", "lib/smartcard/pcsc/ffi_functions.rb", "lib/smartcard/pcsc/ffi_lib.rb", "lib/smartcard/pcsc/ffi_structs.rb", "lib/smartcard/pcsc/pcsc_exception.rb", "lib/smartcard/pcsc/reader_state_queries.rb", "tasks/ffi_codegen.rb", "test/gp/asn1_ber_test.rb", "test/gp/cap_loader_test.rb", "test/gp/des_test.rb", "test/gp/gp_card_mixin_compat_test.rb", "test/gp/gp_card_mixin_test.rb", "test/gp/hello.apdu", "test/gp/hello.cap", "test/iso/auto_configurator_test.rb", "test/iso/iso_card_mixin_test.rb", "test/iso/iso_exception_test.rb", "test/iso/jcop_remote_test.rb", "test/pcsc/card_test.rb", "test/pcsc/context_test.rb", "test/pcsc/reader_state_queries_test.rb", "smartcard.gemspec"]
|
15
14
|
s.homepage = %q{http://www.costan.us/smartcard}
|
16
15
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Smartcard", "--main", "README"]
|
17
|
-
s.require_paths = ["lib"
|
16
|
+
s.require_paths = ["lib"]
|
18
17
|
s.rubyforge_project = %q{smartcard}
|
19
18
|
s.rubygems_version = %q{1.3.5}
|
20
19
|
s.summary = %q{Interface with ISO 7816 smart cards.}
|
21
|
-
s.test_files = ["test/
|
20
|
+
s.test_files = ["test/iso/iso_card_mixin_test.rb", "test/iso/auto_configurator_test.rb", "test/iso/iso_exception_test.rb", "test/iso/jcop_remote_test.rb", "test/pcsc/card_test.rb", "test/pcsc/context_test.rb", "test/pcsc/reader_state_queries_test.rb", "test/gp/gp_card_mixin_test.rb", "test/gp/gp_card_mixin_compat_test.rb", "test/gp/cap_loader_test.rb", "test/gp/asn1_ber_test.rb", "test/gp/des_test.rb"]
|
22
21
|
|
23
22
|
if s.respond_to? :specification_version then
|
24
23
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
25
24
|
s.specification_version = 3
|
26
25
|
|
27
26
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_runtime_dependency(%q<ffi>, [">= 0.5.3"])
|
28
28
|
s.add_runtime_dependency(%q<rubyzip>, [">= 0.9.1"])
|
29
29
|
s.add_runtime_dependency(%q<zerg_support>, [">= 0.1.5"])
|
30
30
|
s.add_development_dependency(%q<echoe>, [">= 3.2"])
|
31
31
|
s.add_development_dependency(%q<flexmock>, [">= 0.8.6"])
|
32
32
|
else
|
33
|
+
s.add_dependency(%q<ffi>, [">= 0.5.3"])
|
33
34
|
s.add_dependency(%q<rubyzip>, [">= 0.9.1"])
|
34
35
|
s.add_dependency(%q<zerg_support>, [">= 0.1.5"])
|
35
36
|
s.add_dependency(%q<echoe>, [">= 3.2"])
|
36
37
|
s.add_dependency(%q<flexmock>, [">= 0.8.6"])
|
37
38
|
end
|
38
39
|
else
|
40
|
+
s.add_dependency(%q<ffi>, [">= 0.5.3"])
|
39
41
|
s.add_dependency(%q<rubyzip>, [">= 0.9.1"])
|
40
42
|
s.add_dependency(%q<zerg_support>, [">= 0.1.5"])
|
41
43
|
s.add_dependency(%q<echoe>, [">= 3.2"])
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# Automatically generates FFI code reflecting headers.
|
2
|
+
#
|
3
|
+
# Author:: Victor Costan
|
4
|
+
# Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'ffi'
|
8
|
+
require 'ffi/tools/const_generator'
|
9
|
+
require 'ffi/tools/struct_generator'
|
10
|
+
require 'set'
|
11
|
+
|
12
|
+
desc 'Regenerate ffi_autogen.rb'
|
13
|
+
task :ffi_header do
|
14
|
+
Smartcard::Tasks.generate_ffi_header
|
15
|
+
end
|
16
|
+
|
17
|
+
# :nodoc: namespace
|
18
|
+
module Smartcard
|
19
|
+
|
20
|
+
module Tasks
|
21
|
+
def self.resolve_constants(pattern, format)
|
22
|
+
if FFI::Platform.mac?
|
23
|
+
header_path = '/System/Library/Frameworks/PCSC.framework/Headers/'
|
24
|
+
else
|
25
|
+
header_path = '/usr/include/PCSC/'
|
26
|
+
end
|
27
|
+
headers = Dir.glob(header_path + '*.h').map { |f| File.basename f }
|
28
|
+
|
29
|
+
consts = Set.new
|
30
|
+
headers.each do |header|
|
31
|
+
File.read("#{header_path}#{header}").each_line do |line|
|
32
|
+
tokens = line.split
|
33
|
+
next unless tokens[0] == '#define'
|
34
|
+
next if tokens[1].index '('
|
35
|
+
consts << tokens[1] if pattern =~ tokens[1]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
const_gen = FFI::ConstGenerator.new(nil,
|
40
|
+
:cppflags => "-w -I#{header_path}") do |g|
|
41
|
+
headers.each { |header| g.include header }
|
42
|
+
consts.each { |const| g.const const, format }
|
43
|
+
end
|
44
|
+
|
45
|
+
const_gen.constants
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.output_constants(constants, f)
|
49
|
+
constants.each do |name, const|
|
50
|
+
f.write " #{const.to_ruby}\n"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.output_enum(enum_name, constants, name_regexp, f)
|
55
|
+
f.write " #{enum_name} = enum [\n"
|
56
|
+
|
57
|
+
re = Regexp.new('^' + name_regexp + '$')
|
58
|
+
constants.each do |name, const|
|
59
|
+
ruby_name = re.match(name)[1]
|
60
|
+
f.write " :#{ruby_name.downcase}, Consts::#{name},\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
f.write " ]\n"
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.generate_ffi_header
|
67
|
+
File.open('lib/smartcard/pcsc/ffi_autogen.rb', 'w') do |f|
|
68
|
+
f.write "# Automatically generated by tasks/ffi_codegen.rb\n\n"
|
69
|
+
|
70
|
+
# Return codes.
|
71
|
+
stat_consts = resolve_constants(/^SCARD_(E|S|W)_.*$/, '0x%08X')
|
72
|
+
# Context scopes.
|
73
|
+
scope_consts = resolve_constants(/^SCARD_SCOPE_/, '0x%08X')
|
74
|
+
# Communication protocols (e.g. T=0).
|
75
|
+
proto_consts = resolve_constants(/^SCARD_PROTOCOL_/, '0x%08X')
|
76
|
+
# Reader sharing modes.
|
77
|
+
share_consts = resolve_constants(/^SCARD_SHARE_/, '0x%08X')
|
78
|
+
# Card dispositions.
|
79
|
+
disp_consts = resolve_constants(/^SCARD_([^_]*)_CARD$/, '0x%08X')
|
80
|
+
# Reader attributes.
|
81
|
+
attr_consts = resolve_constants(/^SCARD_ATTR_/, '0x%08lX')
|
82
|
+
# Card states.
|
83
|
+
card_state_consts = resolve_constants(/^SCARD_STATE_/, '0x%08X')
|
84
|
+
# Reader states.
|
85
|
+
reader_state_consts = resolve_constants(/^SCARD_[^_]*$/, '0x%08X')
|
86
|
+
# Misc constants.
|
87
|
+
misc_consts = resolve_constants(/^MAX_ATR_SIZE|INFINITE$/, '0x%08X')
|
88
|
+
|
89
|
+
f.write "# :nodoc: namespace\n"
|
90
|
+
f.write "module Smartcard::PCSC\n\n"
|
91
|
+
f.write "# :nodoc: auto-generated\n"
|
92
|
+
f.write "module FFILib\n"
|
93
|
+
|
94
|
+
f.write " # Constant values extracted from headers.\n"
|
95
|
+
f.write " module Consts\n"
|
96
|
+
output_constants stat_consts, f
|
97
|
+
output_constants scope_consts, f
|
98
|
+
output_constants proto_consts, f
|
99
|
+
output_constants share_consts, f
|
100
|
+
output_constants disp_consts, f
|
101
|
+
output_constants attr_consts, f
|
102
|
+
output_constants card_state_consts, f
|
103
|
+
output_constants reader_state_consts, f
|
104
|
+
output_constants misc_consts, f
|
105
|
+
f.write " end # module Smartcard::PCSC::FFILib::Consts\n\n"
|
106
|
+
|
107
|
+
f.write " # Error codes returned by the PCSC functions.\n"
|
108
|
+
output_enum 'Status', stat_consts, 'SCARD_._(.*)', f
|
109
|
+
f.write "\n"
|
110
|
+
|
111
|
+
f.write " # Values for the context's scope.\n"
|
112
|
+
output_enum 'Scope', scope_consts, 'SCARD_SCOPE_(.*)', f
|
113
|
+
f.write "\n"
|
114
|
+
|
115
|
+
f.write " # Smart-card communication protocols.\n"
|
116
|
+
output_enum 'Protocol', proto_consts, 'SCARD_PROTOCOL_(.*)', f
|
117
|
+
f.write "\n"
|
118
|
+
|
119
|
+
f.write " # Smart-card sharing modes.\n"
|
120
|
+
output_enum 'Share', share_consts, 'SCARD_SHARE_(.*)', f
|
121
|
+
f.write "\n"
|
122
|
+
|
123
|
+
f.write " # Smart-card dispositions.\n"
|
124
|
+
output_enum 'Disposition', disp_consts, 'SCARD_(.*)_CARD', f
|
125
|
+
f.write "\n"
|
126
|
+
|
127
|
+
f.write " # Smart-card reader attributes.\n"
|
128
|
+
output_enum 'Attribute', attr_consts, 'SCARD_ATTR_(.*)', f
|
129
|
+
f.write "\n"
|
130
|
+
|
131
|
+
f.write " # Smart-card states.\n"
|
132
|
+
output_enum 'CardState', card_state_consts, 'SCARD_STATE_(.*)', f
|
133
|
+
f.write "\n"
|
134
|
+
|
135
|
+
f.write " # Smart-card reader states.\n"
|
136
|
+
output_enum 'State', reader_state_consts, 'SCARD_(.*)', f
|
137
|
+
f.write "\n"
|
138
|
+
|
139
|
+
|
140
|
+
f.write "end # module Smartcard::PCSC::FFILib\n"
|
141
|
+
f.write "end # namespace Smartcard::PCSC\n"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end # namespace Smartcard::Tasks
|
145
|
+
end # namespace Smartcard
|