8
8
9
9
import Foundation
10
10
import CryptoTokenKit
11
- import AppKit
12
11
import MapKit
13
12
14
- let idFile : [ UInt8 ] = [ 0x3F , 0x00 , 0xDF , 0x01 , 0x40 , 0x38 ]
15
- let photoFile : [ UInt8 ] = [ 0x3F , 0x00 , 0xDF , 0x01 , 0x40 , 0x35 ]
16
- let addressFile : [ UInt8 ] = [ 0x3F , 0x00 , 0xDF , 0x01 , 0x40 , 0x33 ]
17
- let basicInfoFile : [ UInt8 ] = [ 0x3F , 0x00 , 0xDF , 0x01 , 0x40 , 0x31 ]
13
+ let idFile : [ UInt8 ] = [ 0xDF , 0x01 , 0x40 , 0x38 ]
14
+ let photoFile : [ UInt8 ] = [ 0xDF , 0x01 , 0x40 , 0x35 ]
15
+ let addressFile : [ UInt8 ] = [ 0xDF , 0x01 , 0x40 , 0x33 ]
16
+ let basicInfoFile : [ UInt8 ] = [ 0xDF , 0x01 , 0x40 , 0x31 ]
18
17
let selectFile : [ UInt8 ] = [ 0 , 0xA4 , 0x08 , 0x0C ]
19
18
let readBinary : [ UInt8 ] = [ 0 , 0xB0 ]
20
19
@@ -48,7 +47,7 @@ class Address: NSObject, MKAnnotation, NSCoding {
48
47
postalCode = aDecoder. decodeObject ( forKey: ArchiveKey . postalColde. rawValue) as! String
49
48
city = aDecoder. decodeObject ( forKey: ArchiveKey . city. rawValue) as! String
50
49
title = aDecoder. decodeObject ( forKey: ArchiveKey . title. rawValue) as? String
51
-
50
+
52
51
let latitude = aDecoder. decodeDouble ( forKey: ArchiveKey . latitude. rawValue)
53
52
let longitude = aDecoder. decodeDouble ( forKey: ArchiveKey . longitude. rawValue)
54
53
coordinate = CLLocationCoordinate2D ( latitude: latitude, longitude: longitude)
@@ -126,17 +125,17 @@ class BasicInfo: NSObject, NSCoding {
126
125
return aDecoder. decodeObject ( forKey: key. rawValue) as! String
127
126
}
128
127
129
- cardNumber = string ( with: . cardNumber)
128
+ cardNumber = string ( with: . cardNumber)
130
129
releasePlace = string ( with: . releasePlace)
131
- firstName = string ( with: . firstName)
132
- lastName = string ( with: . lastName)
133
- otherName = string ( with: . otherName)
134
- nationality = string ( with: . nationality)
135
- birthPlace = string ( with: . birthPlace)
130
+ firstName = string ( with: . firstName)
131
+ lastName = string ( with: . lastName)
132
+ otherName = string ( with: . otherName)
133
+ nationality = string ( with: . nationality)
134
+ birthPlace = string ( with: . birthPlace)
136
135
137
136
validityStart = aDecoder. decodeObject ( forKey: ArchiveKey . validityStart. rawValue) as! Date
138
- validityEnd = aDecoder. decodeObject ( forKey: ArchiveKey . validityEnd. rawValue) as! Date
139
- birthday = aDecoder. decodeObject ( forKey: ArchiveKey . birthday. rawValue) as! Date
137
+ validityEnd = aDecoder. decodeObject ( forKey: ArchiveKey . validityEnd. rawValue) as! Date
138
+ birthday = aDecoder. decodeObject ( forKey: ArchiveKey . birthday. rawValue) as! Date
140
139
141
140
birthNumber = aDecoder. decodeObject ( forKey: ArchiveKey . birthNumber. rawValue) as! UInt16
142
141
}
@@ -192,102 +191,155 @@ extension TKSmartCard {
192
191
case SecurityStatusNotSatisfied, IncorrectLength( expected: UInt8 )
193
192
}
194
193
195
- func read( file: [ UInt8 ] , length: UInt8 , offset: UInt16 = 0 , reply: @escaping ( Data ? , Error ? ) -> Void ) {
194
+ enum ReadResponse {
195
+ case data( Data )
196
+ case error( Error )
197
+ }
198
+
199
+ struct UnknownError : Error { }
200
+
201
+ /// Select a file on the card by path as described in ISO 7816-4
202
+ ///
203
+ /// - Parameter dedicatedFile: Absolute path to dedicated file without the MF Identifier
204
+ func select( dedicatedFile file: [ UInt8 ] , handler reply: @escaping ( Error ? ) -> Void ) {
196
205
self . transmit ( Data ( bytes: selectFile + [ UInt8 ( file. count) ] + file) ) { ( selectFileReply, error) in
197
206
if let error = error {
198
- reply ( nil , error)
207
+ reply ( error)
199
208
} else if let selectFileReply = selectFileReply {
200
209
switch ( selectFileReply [ 0 ] , selectFileReply [ 1 ] ) {
201
210
case ( 0x62 , 0x83 ) :
202
- reply ( nil , SelectFileError . SelectedFileNotActivated)
211
+ reply ( SelectFileError . SelectedFileNotActivated)
203
212
case ( 0x64 , 0 ) :
204
- reply ( nil , CardError . NoPreciseDiagnostic)
213
+ reply ( CardError . NoPreciseDiagnostic)
205
214
case ( 0x65 , 0x81 ) :
206
- reply ( nil , CardError . EepromCorrupted)
215
+ reply ( CardError . EepromCorrupted)
207
216
case ( 0x6A , 0x82 ) :
208
- reply ( nil , SelectFileError . FileNotFound)
217
+ reply ( SelectFileError . FileNotFound)
209
218
case ( 0x6A , 0x86 ) :
210
- reply ( nil , CardError . WrongParameterP1P2)
219
+ reply ( CardError . WrongParameterP1P2)
211
220
case ( 0x6A , 0x87 ) :
212
- reply ( nil , SelectFileError . LcInconsistentWithP1P2)
221
+ reply ( SelectFileError . LcInconsistentWithP1P2)
213
222
case ( 0x69 , 0x99 ) , ( 0x69 , 0x85 ) :
214
- reply ( nil , SelectFileError . AttemptToSelectForbiddenLogicalChannel)
223
+ reply ( SelectFileError . AttemptToSelectForbiddenLogicalChannel)
215
224
case ( 0x6D , 0 ) :
216
- reply ( nil , CardError . CommandNotAvailableWithinCurrentLifeCycle)
225
+ reply ( CardError . CommandNotAvailableWithinCurrentLifeCycle)
217
226
case ( 0x6E , 0 ) :
218
- reply ( nil , SelectFileError . ClaNotSupported)
227
+ reply ( SelectFileError . ClaNotSupported)
219
228
case ( 0x90 , 0 ) :
220
- self . transmit ( Data ( bytes: readBinary + [ UInt8 ( offset >> 8 ) , UInt8 ( offset & 0xff ) , length] ) ) { ( binaryReply, error) in
221
- if let error = error {
222
- print ( error)
223
- } else if let binaryReply = binaryReply {
224
- let statusBytes = ( binaryReply [ binaryReply. endIndex- 2 ] , binaryReply. last!)
225
- switch statusBytes {
226
- case ( 0x64 , 0 ) :
227
- reply ( nil , CardError . NoPreciseDiagnostic)
228
- case ( 0x65 , 0x81 ) :
229
- reply ( nil , CardError . EepromCorrupted)
230
- case ( 0x6B , 0 ) :
231
- reply ( nil , CardError . WrongParameterP1P2)
232
- case ( 0x6D , 0 ) :
233
- reply ( nil , CardError . CommandNotAvailableWithinCurrentLifeCycle)
234
- case ( 0x69 , 0x82 ) :
235
- reply ( nil , ReadBinaryError . SecurityStatusNotSatisfied)
236
- case ( 0x6C , _) :
237
- reply ( nil , ReadBinaryError . IncorrectLength ( expected: binaryReply. last!) )
238
- case ( 0x90 , 0 ) :
239
- reply ( Data ( binaryReply. dropLast ( 2 ) ) , nil )
240
- default : break
241
- }
242
- }
243
- }
244
- default : break
229
+ reply ( nil )
230
+ default :
231
+ reply ( UnknownError ( ) )
245
232
}
246
233
} else {
247
- // TODO: cleanup
234
+ fatalError ( " transmit must either have a response or an error " )
248
235
}
249
236
}
250
237
}
251
238
252
- func readUntilError( file: [ UInt8 ] , data: Data = Data ( bytes: [ ] ) , counter: UInt8 = 0 , updateProgress: ( ( Double ) -> Void ) ? = nil , reply: @escaping ( Data ? , Error ? ) -> Void ) {
253
- let offset = UInt16 ( counter) << 8
254
- updateProgress ? ( Double ( counter) )
255
- read ( file: file, length: 0 , offset: offset) { ( newData, error) in
239
+
240
+ /// Read bytes from current file
241
+ /// as described in section "7.2.3 READ BINARY command" of ISO 7816-4
242
+ ///
243
+ /// - Parameters:
244
+ /// - length: number of bytes to read (Le)
245
+ /// - offset: number of bytes to skip (15-bit unsigned integer, ranging from 0 to 32 767)
246
+ /// - handler: function to execute after completion
247
+ func readBytes( length: UInt8 , offset: UInt16 = 0 , handler: @escaping ( ReadResponse ) -> Void ) {
248
+ self . transmit ( Data ( bytes: readBinary + [ UInt8 ( offset >> 8 ) , UInt8 ( offset & 0xff ) , length] ) ) { ( binaryReply, error) in
256
249
if let error = error {
250
+ print ( error)
251
+ } else if let binaryReply = binaryReply {
252
+ let statusBytes = ( binaryReply [ binaryReply. endIndex- 2 ] , binaryReply. last!)
253
+ switch statusBytes {
254
+ case ( 0x64 , 0 ) :
255
+ handler ( . error( CardError . NoPreciseDiagnostic) )
256
+ case ( 0x65 , 0x81 ) :
257
+ handler ( . error( CardError . EepromCorrupted) )
258
+ case ( 0x6B , 0 ) :
259
+ handler ( . error( CardError . WrongParameterP1P2) )
260
+ case ( 0x6D , 0 ) :
261
+ handler ( . error( CardError . CommandNotAvailableWithinCurrentLifeCycle) )
262
+ case ( 0x69 , 0x82 ) :
263
+ handler ( . error( ReadBinaryError . SecurityStatusNotSatisfied) )
264
+ case ( 0x6C , _) :
265
+ handler ( . error( ReadBinaryError . IncorrectLength ( expected: binaryReply. last!) ) )
266
+ case ( 0x90 , 0 ) :
267
+ handler ( . data(
268
+ Data ( binaryReply. dropLast ( 2 ) )
269
+ ) )
270
+ default :
271
+ handler (
272
+ . error( UnknownError ( ) )
273
+ )
274
+ }
275
+ }
276
+ }
277
+ }
278
+
279
+ func readBytesUntilError( data: Data = Data ( bytes: [ ] ) , updateProgress: ( ( UInt8 ) -> Void ) ? = nil , handler reply: @escaping ( ReadResponse ) -> Void ) {
280
+ let offset = UInt16 ( data. count)
281
+ updateProgress ? ( UInt8 ( offset/ 256 ) )
282
+ readBytes ( length: 0 , offset: offset) {
283
+ switch $0 {
284
+ case . error( let error) :
257
285
switch error {
258
286
case ReadBinaryError . IncorrectLength( let expectedLength) :
259
- self . read ( file: file, length: expectedLength, offset: offset) { ( newData, error) in
260
- updateProgress ? ( Double ( counter+ 1 ) )
261
- if let error = error {
262
- reply ( data, error)
263
- } else if let newData = newData {
287
+ self . readBytes ( length: expectedLength, offset: offset) { response in
288
+ updateProgress ? ( UInt8 ( offset/ 256 ) )
289
+ switch response {
290
+ case . error( let error) :
291
+ reply ( . error( error) )
292
+ case . data( let newData) :
264
293
var concat = Data ( )
265
294
concat. reserveCapacity ( data. count+ newData. count)
266
295
concat. append ( data)
267
296
concat. append ( newData)
268
- reply ( concat, nil )
297
+ reply ( . data ( concat) )
269
298
}
270
299
}
300
+ case CardError . WrongParameterP1P2:
301
+ if data. count > 0 {
302
+ reply ( . data( data) )
303
+ } else {
304
+ reply ( . error( error) )
305
+ }
271
306
default :
272
- reply ( data , error)
307
+ reply ( . error( error ) )
273
308
}
274
- } else if let newData = newData {
309
+ case . data ( let newData) :
275
310
var concat = Data ( )
276
311
concat. reserveCapacity ( data. count+ newData. count)
277
312
concat. append ( data)
278
313
concat. append ( newData)
279
- self . readUntilError ( file: file, data: concat, counter: counter+ 1 , updateProgress: updateProgress) { ( data, error) in
280
- reply ( data, error)
314
+ if newData. count < 256 {
315
+ reply ( . data( concat) )
316
+ } else {
317
+ self . readBytesUntilError ( data: concat, updateProgress: updateProgress, handler: reply)
281
318
}
282
319
}
283
320
}
284
321
}
285
322
323
+ /// Select dedicated file and read all its bytes. This is a helper function that combines the SELECT (section 7.1.1) & READ BINARY (section 7.2.3) commands from ISO 7816-4.
324
+ ///
325
+ /// - Parameters:
326
+ /// - file: Absolute path to dedicated file without the MF Identifier
327
+ /// - updateProgress: function that gets called while reading the large files and informs the progress of the read command
328
+ /// - reply: function that gets called when the file is read
329
+ func read( file: [ UInt8 ] , updateProgress: ( ( UInt8 ) -> Void ) ? = nil , reply: @escaping ( ReadResponse ) -> Void ) {
330
+ select ( dedicatedFile: file) {
331
+ if let error = $0 {
332
+ reply ( . error( error) )
333
+ } else {
334
+ self . readBytesUntilError ( updateProgress: updateProgress, handler: reply)
335
+ }
336
+ }
337
+ }
338
+
286
339
func getAddress( geocodeCompletionHandler: @escaping CLGeocodeCompletionHandler = { ( _, _) in } , reply: @escaping ( _ address: Address ? , _ error: Error ? ) -> Void ) {
287
- readUntilError ( file: addressFile) { ( data, error) in
288
- if let error = error {
289
- reply ( nil , error)
290
- } else if let data = data {
340
+ read ( file: addressFile) { response in
341
+ switch response {
342
+ case . data( let data) :
291
343
let street = 2 ..< Int ( data [ 1 ] ) + 2
292
344
let postalCode = street. upperBound + 2 ..< street. upperBound + Int( data [ street. upperBound+ 1 ] ) + 2
293
345
let city = postalCode. upperBound + 2 ..< postalCode. upperBound + Int( data [ postalCode. upperBound+ 1 ] ) + 2
@@ -297,23 +349,26 @@ extension TKSmartCard {
297
349
String ( bytes: data [ postalCode] , encoding: . utf8) !,
298
350
String ( bytes: data [ city] , encoding: . utf8) !
299
351
) , title: NSLocalizedString ( " Domicile " , comment: " Domicile " ) , geocodeCompletionHandler: geocodeCompletionHandler) , nil )
352
+ case . error( let error) :
353
+ reply ( nil , error)
300
354
}
301
355
}
302
356
}
303
357
304
358
305
359
func getBasicInfo( reply: @escaping ( BasicInfo ? , Error ? ) -> Void ) {
306
- readUntilError ( file: basicInfoFile) { ( data, error) in
307
- if let error = error {
360
+ read ( file: basicInfoFile) { response in
361
+ switch response {
362
+ case . error( let error) :
308
363
reply ( nil , error)
309
- } else if let data = data {
364
+ case . data ( let data) :
310
365
reply ( BasicInfo ( from: data) , nil )
311
366
}
312
367
}
313
368
}
314
369
315
- func getProfileImage( updateProgress: ( ( Double ) -> Void ) ? = nil , reply: @escaping ( Data ? , Error ? ) -> Void ) {
316
- readUntilError ( file: photoFile, updateProgress: updateProgress, reply: reply)
370
+ func getProfileImage( updateProgress: ( ( UInt8 ) -> Void ) ? = nil , reply: @escaping ( ReadResponse ) -> Void ) {
371
+ read ( file: photoFile, updateProgress: updateProgress, reply: reply)
317
372
}
318
373
}
319
374
@@ -339,3 +394,4 @@ extension DateFormatter {
339
394
self . dateStyle = style
340
395
}
341
396
}
397
+
0 commit comments