iso7816 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,68 @@
1
+ module ISO7816
2
+
3
+ module APDU
4
+
5
+ def APDU.create_class name, ins
6
+ cl=
7
+ %Q(
8
+ class #{name} < APDU
9
+ cla \"\\x00\"
10
+ ins \"\\x#{ins}\"
11
+ end
12
+ )
13
+ eval(cl)
14
+ end
15
+
16
+ [
17
+ ["ACTIVATE_FILE", "44"],
18
+ ["APPEND_RECORD", "E2"],
19
+ ["CHANGE_REFERENCE_DATA", "24"],
20
+ ["CREATE_FILE", "E0"],
21
+ ["DEACTIVATE_FILE", "04"],
22
+ ["DELETE_FILE", "E4"],
23
+ ["DISABLE_VERIFICATION_REQUIREMENT", "26"],
24
+ ["ENABLE_VERIFICATION_REQUIREMENT", "28"],
25
+ ["ENVELOPE", "C2"],
26
+ ["ERASE_BINARY", "0E"],
27
+ ["ERASE_RECORD", "0C"],
28
+ ["EXTERNAL_AUTHENTICATE", "82"],
29
+ ["GENERAL_AUTHENTICATE", "86"],
30
+ ["GENERATE_ASYMMETRIC_KEY_PAIR", "46"],
31
+ ["GET_CHALLENGE", "84"],
32
+ ["GET_DATA", "CA"],
33
+ ["GET_RESPONSE", "C0"],
34
+ ["INTERNAL_AUTHENTICATE", "88"],
35
+ ["MANAGE_CHANNEL", "70"],
36
+ ["MANAGE_SECURITY_ENVIRONMENT", "22"],
37
+ ["PERFORM_SCQL_OPERATION", "10"],
38
+ ["PERFORM_SECURITY_OPERATION", "2A"],
39
+ ["PERFORM_TRANSACTION_OPERATION", "12"],
40
+ ["PERFORM_USER_OPERATION", "14"],
41
+ ["PUT_DATA", "DA"],
42
+ ["READ_BINARY", "B0"],
43
+ ["READ_RECORD", "B2"],
44
+ ["RESET_RETRY_COUNTER", "2C"],
45
+ ["SEARCH_BINARY", "A0"],
46
+ ["SEARCH_RECORD", "A2"],
47
+ ["SELECT", "A4"],
48
+ ["TERMINATE_CARD_USAGE", "FE"],
49
+ ["TERMINATE_DF", "E6"],
50
+ ["TERMINATE_EF", "E8"],
51
+ ["UPDATE_BINARY", "D6"],
52
+ ["UPDATE_RECORD", "DC"],
53
+ ["VERIFY", "20"],
54
+ ["WRITE_BINARY", "D0"],
55
+ ["WRITE_RECORD", "D2"]
56
+ ].each{|entry|
57
+ APDU.create_class *entry
58
+ }
59
+
60
+
61
+ class GET_RESPONSE < APDU
62
+ ins "\xc0"
63
+ end
64
+
65
+
66
+ end # APDU
67
+
68
+ end #7816
@@ -0,0 +1,102 @@
1
+ require 'smartcard'
2
+ module ISO7816
3
+ module PCSC
4
+
5
+ # adds default params to Smartcard to make them easier to work with.
6
+
7
+ class Context < Smartcard::PCSC::Context
8
+ def initialize scope=Smartcard::PCSC::SCOPE_SYSTEM
9
+ super
10
+ end
11
+
12
+ def list_readers reader_groups=nil
13
+ super
14
+ end
15
+ end
16
+
17
+ class Card < Smartcard::PCSC::Card
18
+ include Smartcard::PCSC
19
+ attr_accessor :ctx
20
+ def initialize( context = nil,
21
+ reader_name = nil,
22
+ share_mode = SHARE_EXCLUSIVE,
23
+ preferred_protocol = PROTOCOL_ANY)
24
+
25
+ @ctx = context || ISO7816::PCSC::Context.new
26
+ @r_name = reader_name || @ctx.list_readers()[0]
27
+ @share_mode = share_mode
28
+ @preferred_protocol = preferred_protocol
29
+
30
+ super(@ctx, @r_name, @share_mode, @preferred_protocol)
31
+ end
32
+
33
+ def disconnect disposition=DISPOSITION_UNPOWER, release_context=true
34
+ super(disposition)
35
+ @ctx.release if release_context
36
+ end
37
+
38
+ def reconnect share=nil, preferred_protocol=nil, ini= INITIALIZATION_UNPOWER
39
+ # use and remember passed params if set, else reuse last remembered params.
40
+ share ||= @share_mode
41
+ preferred_protocol ||= @preferred_protocol
42
+
43
+ @share_mode = share
44
+ @preferred_protocol = preferred_protocol
45
+
46
+ @status = nil
47
+ #puts @share_mode.class
48
+ #puts @preferred_protocol.class
49
+ #puts ini.class
50
+ super(@share_mode, @preferred_protocol, ini)
51
+ end
52
+
53
+ def _status
54
+ @status ||= self.status
55
+ end
56
+
57
+ def transmit send_data, send_io_request=nil, recv_io_request=nil
58
+ unless send_io_request
59
+ protocol = _status[:protocol]
60
+ send_io_request = case protocol
61
+ when PROTOCOL_T0:
62
+ IOREQUEST_T0
63
+ when PROTOCOL_T1:
64
+ puts "T1"
65
+ IOREQUEST_T1
66
+ when Smartcard::PCSC::PROTOCOL_RAW:
67
+ IOREQUEST_RAW
68
+ else
69
+ raise "weird protocol: #{protocol}"
70
+ end
71
+ end # send_io_request
72
+
73
+ recv_io_request ||= Smartcard::PCSC::IoRequest.new
74
+ super(send_data, send_io_request, recv_io_request)
75
+ end
76
+
77
+ def atr
78
+ _status[:atr]
79
+ end
80
+ def protocol?
81
+ case _status[:protocol]
82
+ when PROTOCOL_T0
83
+ "T0"
84
+ when PROTOCOL_T1
85
+ "T1"
86
+ when PROTOCOL_RAW
87
+ "RAW"
88
+ when PROTOCOL_T15
89
+ "T15"
90
+ when PROTOCOL_UNKNOWN
91
+ "UNKNOWN"
92
+ else
93
+ "UNKNOWN_UNKNOWN"
94
+ end
95
+ end
96
+ end #card
97
+
98
+ end # pcsc
99
+ end # iso7816
100
+
101
+
102
+
@@ -0,0 +1,10 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'iso7816'
5
+ require 'emv/emv'
6
+ require 'emv/emv_apdu'
7
+ require 'emv/cps_apdu'
8
+ require 'emv/data/cps_ini_update'
9
+ require 'emv/crypto/crypto'
10
+
@@ -0,0 +1,319 @@
1
+ module EMV
2
+ module APDU
3
+ module CPS
4
+
5
+
6
+ class SecureContext
7
+ # The Kenc key used in this session
8
+ attr_accessor :k_enc
9
+
10
+ # The Kmac key used in this session
11
+ attr_accessor :k_mac
12
+
13
+ # The Kdek key used in this session
14
+ attr_accessor :k_dek
15
+
16
+ # The challenge sent to the card, (Rterm)
17
+ attr_accessor :host_challenge
18
+
19
+ # The session key SKUenc
20
+ attr_accessor :sku_enc
21
+
22
+ attr_accessor :sku_mac
23
+ attr_accessor :sku_dek
24
+
25
+ # The card's response to initialize update containing:
26
+ # kmc_id (Identifier of the KMC)
27
+ # csn (Chip Serial Number)
28
+ # kmc_version (Version Number of Master key (KMC))
29
+ # sec_channel_proto_id (Identifier of Secure Channel Protocol)
30
+ # sequence_counter (Sequence Counter)
31
+ # challenge (Card challenge (r card))
32
+ # cryptogram (Card Cryptogram)
33
+
34
+ attr_reader :initialize_response
35
+
36
+ # The security level established by the EXTERNAL_AUTH command
37
+ # According to CPS Table 19
38
+ # One of:
39
+ # :enc_and_mac
40
+ # :mac
41
+ # :no_sec
42
+ attr_accessor :level
43
+
44
+
45
+ def initialize k_enc="\x00"*16, k_mac="\x00"*16, k_dek="\x00"*16, host_challenge="\x00"*8
46
+ @k_enc = k_enc
47
+ @k_mac = k_mac
48
+ @k_dek = k_dek
49
+
50
+ @host_challenge=host_challenge
51
+ @level = :no_sec
52
+ end
53
+
54
+ # Set the response returned by INITIALIZE UPDATE.
55
+ # * calculates the Session keys.
56
+ def initialize_response= resp
57
+
58
+ @initialize_response = resp
59
+
60
+
61
+ @sku_enc = EMV::Crypto.generate_session_key(k_enc,
62
+ @initialize_response.sequence_counter,
63
+ :enc)
64
+ @sku_mac = EMV::Crypto.generate_session_key(k_mac,
65
+ @initialize_response.sequence_counter,
66
+ :mac)
67
+
68
+ @sku_dek = EMV::Crypto.generate_session_key(k_dek,
69
+ @initialize_response.sequence_counter,
70
+ :dek)
71
+ end
72
+
73
+ # Verify the cryptogram sent by the card according to: CPS 3.2.5.10
74
+ def check_card_cryptogram
75
+ mac_ = host_challenge +
76
+ initialize_response.sequence_counter +
77
+ initialize_response.challenge
78
+
79
+ mac = EMV::Crypto.mac_for_personalization(sku_enc, mac_)
80
+ unless mac == initialize_response.cryptogram
81
+ raise %Q{
82
+ Invalid MAC returned from card!
83
+ host challenge: #{ISO7816.b2s(host_challenge)}
84
+ card seq : #{ISO7816.b2s(initialize_response.sequence_counter)}
85
+ card challenge: #{ISO7816.b2s(initialize_response.challenge)}
86
+ expected mac : #{ISO7816.b2s(mac)}
87
+ recv mac : #{ISO7816.b2s(initialize_response.cryptogram)}
88
+ k_enc : #{ISO7816.b2s(k_enc)}
89
+ k_mac : #{ISO7816.b2s(k_mac)}
90
+ k_dek : #{ISO7816.b2s(k_dek)}
91
+ }
92
+ end
93
+ end
94
+
95
+ # Calculates the host cryptogram according to CPS 3.2.6.6
96
+ def calculate_host_cryptogram
97
+ mac_ = initialize_response.sequence_counter +
98
+ initialize_response.challenge +
99
+ host_challenge
100
+ EMV::Crypto.mac_for_personalization(sku_enc, mac_)
101
+ end
102
+
103
+ # Calculate the C-MAC according to CP 5.4.2.2
104
+ def calculate_c_mac apdu
105
+ # data with placeholder for cmac
106
+ data = apdu.data
107
+ mac_ = apdu.cla +
108
+ apdu.ins +
109
+ apdu.p1 +
110
+ apdu.p2
111
+
112
+ mac_ << apdu.data.length+8
113
+ mac_ << data
114
+ if @c_mac # "prepend the c-mac computed for the previous command ..."
115
+ mac_ = @c_mac + mac_
116
+ end
117
+ @c_mac = EMV::Crypto.retail_mac(sku_mac, mac_)
118
+ @c_mac
119
+ end
120
+
121
+ # Retrieve the current seq number, this also increments the counter.
122
+ def store_data_seq_number
123
+ @store_data_seq_number ||= -1
124
+ @store_data_seq_number += 1
125
+ "" << @store_data_seq_number
126
+ end
127
+
128
+ def reset
129
+ @c_mac = nil
130
+ @store_data_seq_number = nil
131
+ @sku_enc = nil
132
+ @sku_mac = nil
133
+ @initialize_response = nil
134
+ end
135
+
136
+ # Encrypt data bytes according to CPS 5.5.2
137
+ def encrypt data
138
+ data = EMV::Crypto.pad data
139
+ cipher = OpenSSL::Cipher::Cipher.new("des-ede-cbc").encrypt
140
+ cipher.key = sku_enc
141
+ cipher.update data
142
+ end
143
+ end
144
+
145
+ class CPS_APDU < EMV::APDU::EMV_APDU
146
+ attr_accessor :secure_context
147
+
148
+ def initialize card, secure_context
149
+ super card
150
+ @secure_context= secure_context
151
+ end
152
+ end
153
+ class INITIALIZE_UPDATE < CPS_APDU
154
+ ins "\x50"
155
+
156
+ def key_version_number= kvn
157
+ self.p1= kvn
158
+ end
159
+ def send handle_more_data=true, card=nil
160
+ secure_context.reset
161
+ @data = secure_context.host_challenge
162
+
163
+ resp = super
164
+ if resp.status == "9000"
165
+ @secure_context.initialize_response = EMV::Data::InitializeUpdateData.new(resp.data)
166
+ @secure_context.check_card_cryptogram
167
+ end
168
+ resp
169
+ end
170
+ end
171
+
172
+ class C_MAC_APDU < CPS_APDU
173
+ # Provides the possibility to override the calculated c_mac
174
+ # with an arbitrary one for testing.
175
+ attr_writer :c_mac
176
+
177
+ def initialize card, secure_context
178
+ super
179
+ end
180
+
181
+ # calculate the c-mac according to 5.4.2.2
182
+ def c_mac
183
+ @c_mac ||= secure_context.calculate_c_mac(self)
184
+ @c_mac
185
+ end
186
+ end
187
+
188
+ class EXTERNAL_AUTHENTICATE < C_MAC_APDU
189
+ cla "\x84"
190
+ ins "\x82"
191
+ def initialize card, secure_context
192
+ super
193
+ self.security_level= secure_context.level if secure_context.level
194
+ end
195
+
196
+ #
197
+ # CPS 3.2.6
198
+ # :enc_and_mac
199
+ # :mac
200
+ # :no_sec
201
+ # or a sec level byte...
202
+ def security_level= level
203
+ case level
204
+ when :enc_and_mac
205
+ self.p1= 0x03
206
+ when :mac
207
+ self.p1= 0x01
208
+ when :no_sec
209
+ self.p1= 0x00
210
+ else
211
+ self.p1=level
212
+ end
213
+ @secure_context.level= level
214
+ end
215
+
216
+ #
217
+ # Sets the host cryptogram according to CPS 3.2.6.6
218
+ #
219
+ def cryptogram
220
+ @cryptogram ||= secure_context.calculate_host_cryptogram
221
+ @cryptogram
222
+ end
223
+
224
+ # Explicitly set a cryptogram, e.g. if an incorrect cryptogram is to be set
225
+ # for testing.
226
+ def cryptogram= bytes
227
+ @cryptogram= bytes
228
+ end
229
+
230
+
231
+ def send handle_more_data=true, card=nil
232
+ @data= self.cryptogram
233
+ @data+= c_mac # calculate the c_mac...
234
+ super
235
+ end
236
+
237
+
238
+ end
239
+ class STORE_DATA < C_MAC_APDU
240
+ ins "\xE2"
241
+
242
+ LAST_STORE_DATA_MASK = 0x80
243
+ ALL_DGI_ENC_MASK = 0x60
244
+ NO_DGI_ENC_MASK = 0x00
245
+ APP_DEPENDANT_MASK = 0x20
246
+
247
+ SECURE_MASK = 0x04
248
+
249
+ attr_reader :security_level
250
+
251
+ def initialize card, secure_context, data=""
252
+ super(card, secure_context)
253
+ #@security_level = secure_context.level
254
+ @cla= "\x84" if @security_level == :enc_and_mac
255
+ self.data= data
256
+ end
257
+ def security_level= level
258
+ @security_level = level
259
+ if [:enc_and_mac, :mac].include? level
260
+ secure
261
+ else
262
+ self.cla = 0x80
263
+ end
264
+ end
265
+ def secure
266
+ self.cla= cla[0] | SECURE_MASK
267
+ end
268
+ def secure?
269
+ (cla[0] & SECURE_MASK) == SECURE_MASK
270
+ end
271
+ def last_store_data
272
+ self.p1= (p1[0] | LAST_STORE_DATA_MASK)
273
+ end
274
+ def last_store_data?
275
+ (p1[0] & LAST_STORE_DATA_MASK) == LAST_STORE_DATA_MASK
276
+ end
277
+ def all_dgi_enc
278
+ self.p1= (p1[0] | ALL_DGI_ENC_MASK)
279
+ end
280
+ def all_dgi_enc?
281
+ (p1[0] & ALL_DGI_ENC_MASK) == ALL_DGI_ENC_MASK
282
+ end
283
+ def no_dgi_enc
284
+ self.p1= (p1[0] & ~ ALL_DGI_ENC_MASK)
285
+ end
286
+ def no_dgi_enc?
287
+ (p1[0] & NO_DGI_ENC_MASK) == NO_DGI_ENC_MASK
288
+ end
289
+ def app_dependant
290
+ self.p1= (p1[0] & ~ ALL_DGI_ENC_MASK) | APP_DEPENDANT_MASK
291
+ end
292
+ def app_dependant?
293
+ (p1[0] & APP_DEPENDANT_MASK) == APP_DEPENDANT_MASK
294
+ end
295
+
296
+ def send handle_more_data=true, card=nil
297
+
298
+ @p2 = secure_context.store_data_seq_number
299
+
300
+ # Secure Ctx security level may change in the course of a series of
301
+ # apdus, so we only no the current state just before sending.
302
+ self.security_level= @secure_context.level unless @security_level
303
+
304
+ unless @security_level == :no_sec
305
+ c_mac_ = self.c_mac # c_mac is calculated over unencrypted data
306
+ if @security_level == :enc_and_mac
307
+ @data= secure_context.encrypt(self.data)+c_mac_
308
+ else
309
+ @data= self.data+c_mac_
310
+ end
311
+ end
312
+ super
313
+ end
314
+
315
+ end
316
+
317
+ end #CPS
318
+ end # APDU
319
+ end #EMV