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