Skip to content

Commit 7e75fe8

Browse files
authored
YubiKit 4.1 (#71)
* Add timestamp to calculate OATH OTP. * Add timestamp to calculate-all OATH OTP. * Make version public in YKFManagementSession. * If a connection is present when the delegate is set on the YubiKitManager it will immediately call the didConnect delegate methods. * Refactored Management session to use TKTLVRecord instead of our own tlv-parsing. * Removed extra dot at end of version string. * Forgot to make delegate weak when moving it to a class variable. * Fixed bug that made it impossible to unlock with password if a command had failed with not authenticated. * Added stopWithErrorMessage: to nfc connection. * Added stopNFCConnectionWithErrorMessage: to YubiKitManager. * Improved Swift method translation. * Added stopNFCConnectionWithMessage: to YubiKitManager. * Forgot implementation of stopWithMessage:. * Added dispatchAfterCurrentCommands to sessions to enable running a code block after all enqueued commands have completed. * Only signal NFC disconnect if previous state was YKFNFCConnectionStateOpen. * Send proper error codes when unlocking the OATH application * Remove unused error definition. * Remove unused files from project file as well. * Return defined errors for wrong pin and pin entry locked. * Less fragile comparision of algorithm type. * Fixed bug when we tried to calculate more than 8 OATH credentials. * Accidentally sent a auth required error instead of touch timeout. * Fixed bug in authentication/touch timeout error handling. * Reverted to previous behaviour where we singaled an error for NFC modal timeout and user cancel. * New delegate method to catch NFC timeout and user cancelling the NFC modal. * Make the didFailConnectingNFC method optional in the connection protocol. * Fix broken non-trunkated calculation of OATH code. * Remove broken OATH tests. * Improved error checks and fixes a bug where authenticateWithManagementKey would fail to call its completion handler upon failure. * Improved array out of bounds checks and more cautious logging. * Bumped version number to 4.1.0 and updated changes.
1 parent fcceff9 commit 7e75fe8

File tree

72 files changed

+1210
-721
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1210
-721
lines changed

Changelog.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# YubiKit Changelog
22

3+
## 4.1.0
4+
5+
- Optional timestamp parameter added to OATH calculate and calculateAll methods.
6+
- Firmware version is now a public variable on `YKFManagementSession`.
7+
- If a connection is already present when setting the `YKFManagerDelegate` it will return that connection immideatly.
8+
- Extra dot at the end of `YKFVersion` string removed.
9+
- Fixed memory issues where we retained the `YKFManagerDelegate`.
10+
- Fixed issue where failing to unlock a key with passcode before sending an OATH command got the session in a non recoverable state.
11+
- Improved control over the messages displayed in the NFC dialog.
12+
- Added `- (void)dispatchBlockOnCommunicationQueue:(YKFConnectionControllerCommunicationQueueBlock)block` to `YKFConnectionControllerProtocol` that will run a block after all enqueued commands has finished.
13+
- Improved error handling in OATH session.
14+
- More robust algorithm comparison in PIV session.
15+
- Fixed bug where an auth required error was sent instead of touch timeout in OATH session.
16+
- Fixed bug where the number of OATH accounts you could read was limited to around 8
17+
- Added new optional connection delegate method that will signal if the NFC dialog was cancelled by the user or timed out.
18+
- Swift package manager header files exluded from Cocoapod distribution.
19+
- Various array out of bounds checks
20+
- Improved error checks
21+
- Fixes bug where authenticateWithManagementKey in the YKFPIVSession would fail to call its completion handler upon failure.
22+
- Fixes broken implementation of non truncated OATH codes
23+
324
## 4.0.0
425

526
This release breaks backwards compatibility with previous versions of the SDK. The reason for this is to make the SDK easier to

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Add YubiKit to your [Podfile](https://guides.cocoapods.org/using/the-podfile.htm
5151
```ruby
5252
use_frameworks!
5353

54-
pod 'YubiKit', '~> 4.0.0'
54+
pod 'YubiKit', '~> 4.1.0'
5555

5656
```
5757
If you want to have latest changes, replace the last line with:

YubiKit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'YubiKit'
3-
s.version = '4.0.0'
3+
s.version = '4.1.0'
44
s.license = 'Apache 2.0'
55
s.summary = 'YubiKit is an iOS library provided by Yubico to interact with YubiKeys on iOS devices.'
66
s.homepage = 'https://github.com/Yubico/yubikit-ios'

YubiKit/YubiKit.xcodeproj/project.pbxproj

Lines changed: 20 additions & 28 deletions
Large diffs are not rendered by default.

YubiKit/YubiKit/Connections/AccessoryConnection/YKFAccessoryConnection+Private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ typedef void (^YKFAccessoryConnectionStateChangeBlock)(YKFAccessoryConnectionSta
2929

3030
@interface YKFAccessoryConnection()
3131

32+
@property (nonatomic, readonly) YKFAccessoryConnectionState state;
3233
@property(nonatomic, weak) id<YKFAccessoryConnectionDelegate> _Nullable delegate;
3334

3435
/*

YubiKit/YubiKit/Connections/AccessoryConnection/YKFAccessoryConnection.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ - (instancetype)initWithAccessoryManager:(id<YKFEAAccessoryManagerProtocol>)acce
117117
return self;
118118
}
119119

120+
- (YKFAccessoryConnectionState)state {
121+
return _connectionState;
122+
}
123+
120124
- (YKFSmartCardInterface *)smartCardInterface {
121125
if (!self.connectionController) {
122126
return nil;

YubiKit/YubiKit/Connections/AccessoryConnection/YKFAccessoryConnectionController.m

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
#import "YKFSessionError+Private.h"
2424
#import "YKFAPDU+Private.h"
2525

26-
typedef void (^YKFConnectionControllerCommunicationQueueBlock)(NSOperation *operation);
27-
2826
@interface YKFAccessoryConnectionController()
2927

3028
@property (nonatomic) NSOperationQueue *communicationQueue;
@@ -310,43 +308,6 @@ - (void)execute:(YKFAPDU *)command timeout:(NSTimeInterval)timeout completion:(Y
310308
}];
311309
}
312310

313-
- (void)dispatchOnSequentialQueue:(YKFConnectionControllerCompletionBlock)block delay:(NSTimeInterval)delay {
314-
dispatch_queue_t sharedDispatchQueue = self.communicationQueue.underlyingQueue;
315-
316-
YKFParameterAssertReturn(sharedDispatchQueue);
317-
YKFParameterAssertReturn(block);
318-
319-
block = [block copy]; // heap block
320-
321-
if (delay == 0) {
322-
dispatch_async(sharedDispatchQueue, block);
323-
} else {
324-
NSString *blockId = [NSUUID UUID].UUIDString;
325-
326-
ykf_weak_self();
327-
dispatch_block_t delayedBlock = dispatch_block_create(0, ^{
328-
ykf_safe_strong_self();
329-
dispatch_block_t blockReference = strongSelf.delayedDispatches[blockId];
330-
strongSelf.delayedDispatches[blockId] = nil;
331-
332-
// In case the block started already to run.
333-
if (blockReference && dispatch_block_testcancel(blockReference)) {
334-
return;
335-
}
336-
337-
block();
338-
});
339-
340-
self.delayedDispatches[blockId] = delayedBlock;
341-
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), sharedDispatchQueue, delayedBlock);
342-
}
343-
}
344-
345-
- (void)dispatchOnSequentialQueue:(YKFConnectionControllerCompletionBlock)block {
346-
YKFParameterAssertReturn(block);
347-
[self dispatchOnSequentialQueue:block delay:0];
348-
}
349-
350311
- (void)cancelAllCommands {
351312
self.communicationQueue.suspended = YES;
352313
dispatch_suspend(self.communicationQueue.underlyingQueue);

YubiKit/YubiKit/Connections/NFCConnection/YKFNFCConnection+Private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121

2222
- (void)didConnectNFC:(YKFNFCConnection *_Nonnull)connection;
2323
- (void)didDisconnectNFC:(YKFNFCConnection *_Nonnull)connection error:(NSError *_Nullable)error;
24+
- (void)didFailConnectingNFC:(NSError *_Nonnull)error;
2425

2526
@end
2627

2728
@interface YKFNFCConnection()
2829

30+
@property (nonatomic, readonly) YKFNFCConnectionState state;
2931
@property(nonatomic, weak) id<YKFNFCConnectionDelegate> _Nullable delegate;
3032

3133
@end

YubiKit/YubiKit/Connections/NFCConnection/YKFNFCConnection.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,22 @@ typedef NS_ENUM(NSUInteger, YKFNFCConnectionState) {
7373
*/
7474
- (void)stop API_AVAILABLE(ios(13.0));
7575

76+
/*!
77+
@method stopWithMessage:
78+
79+
@abstract
80+
Closes the communication with the key and display a message.
81+
*/
82+
- (void)stopWithMessage:(NSString *)message API_AVAILABLE(ios(13.0));
83+
84+
/*!
85+
@method stopWithErrorMessage:
86+
87+
@abstract
88+
Closes the communication with the key and display an error message.
89+
*/
90+
- (void)stopWithErrorMessage:(NSString *)errorMessage API_AVAILABLE(ios(13.0));
91+
7692
/*!
7793
@method cancelCommands
7894

YubiKit/YubiKit/Connections/NFCConnection/YKFNFCConnection.m

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ - (instancetype)init {
6969
return self;
7070
}
7171

72+
- (YKFNFCConnectionState)state {
73+
return _nfcConnectionState;
74+
}
75+
7276
- (YKFSmartCardInterface *)smartCardInterface {
7377
if (!self.connectionController) {
7478
return nil;
@@ -162,9 +166,29 @@ - (void)stop API_AVAILABLE(ios(13.0)) {
162166
}
163167

164168
[self setAlertMessage:YubiKitExternalLocalization.nfcScanSuccessAlertMessage];
165-
[self updateServicesForSession:self.nfcTagReaderSession tag:nil state:YKFNFCConnectionStateClosed];
169+
[self updateServicesForSession:self.nfcTagReaderSession tag:nil state:YKFNFCConnectionStateClosed errorMessage:nil];
170+
}
171+
172+
- (void)stopWithMessage:(NSString *)message API_AVAILABLE(ios(13.0)) {
173+
if (!self.nfcTagReaderSession) {
174+
YKFLogInfo(@"NFC session already stopped. Ignoring stop request.");
175+
return;
176+
}
177+
178+
[self setAlertMessage:message];
179+
[self updateServicesForSession:self.nfcTagReaderSession tag:nil state:YKFNFCConnectionStateClosed errorMessage:nil];
180+
}
181+
182+
- (void)stopWithErrorMessage:(NSString *)errorMessage API_AVAILABLE(ios(13.0)) {
183+
if (!self.nfcTagReaderSession) {
184+
YKFLogInfo(@"NFC session already stopped. Ignoring stop request.");
185+
return;
186+
}
187+
188+
[self updateServicesForSession:self.nfcTagReaderSession tag:nil state:YKFNFCConnectionStateClosed errorMessage:errorMessage];
166189
}
167190

191+
168192
- (void)cancelCommands API_AVAILABLE(ios(13.0)) {
169193
[self.connectionController cancelAllCommands];
170194
}
@@ -204,7 +228,7 @@ - (void)tagReaderSession:(NFCTagReaderSession *)session didInvalidateWithError:(
204228
- (void)tagReaderSessionDidBecomeActive:(NFCTagReaderSession *)session API_AVAILABLE(ios(13.0)) {
205229
YKFLogInfo(@"NFC session did become active.");
206230
self.nfcTagReaderSession = session;
207-
[self updateServicesForSession:session tag:nil state:YKFNFCConnectionStatePolling];
231+
[self updateServicesForSession:session tag:nil state:YKFNFCConnectionStatePolling errorMessage:nil];
208232
}
209233

210234
- (void)tagReaderSession:(NFCTagReaderSession *)session didDetectTags:(NSArray<__kindof id<NFCTag>> *)tags API_AVAILABLE(ios(13.0)) {
@@ -240,7 +264,7 @@ - (void)tagReaderSession:(NFCTagReaderSession *)session didDetectTags:(NSArray<_
240264
}
241265

242266
YKFLogInfo(@"NFC session did connect to tag.");
243-
[strongSelf updateServicesForSession:session tag:activeTag state:YKFNFCConnectionStateOpen];
267+
[strongSelf updateServicesForSession:session tag:activeTag state:YKFNFCConnectionStateOpen errorMessage:nil];
244268
}];
245269
}
246270

@@ -258,27 +282,38 @@ - (void)updateServicesForSession:(NFCTagReaderSession *)session error:(NSError *
258282

259283
self.nfcConnectionError = error;
260284
[self.nfcTagReaderSession invalidateSessionWithErrorMessage:error.localizedDescription];
261-
[self updateServicesForSession:session tag:nil state:YKFNFCConnectionStateClosed];
285+
[self updateServicesForSession:session tag:nil state:YKFNFCConnectionStateClosed errorMessage:nil];
262286
}
263287

264-
- (void)updateServicesForSession:(NFCTagReaderSession *)session tag:(id<NFCISO7816Tag>)tag state:(YKFNFCConnectionState)state API_AVAILABLE(ios(13.0)) {
288+
- (void)updateServicesForSession:(NFCTagReaderSession *)session tag:(id<NFCISO7816Tag>)tag state:(YKFNFCConnectionState)state errorMessage:(NSString *)errorMessage API_AVAILABLE(ios(13.0)) {
265289
if (self.nfcConnectionState == state) {
266290
return;
267291
}
268292
if (self.nfcTagReaderSession != session) {
269293
return;
270294
}
271295

296+
YKFNFCConnectionState previousState = self.nfcConnectionState;
297+
self.nfcConnectionState = state;
298+
272299
switch (state) {
273300
case YKFNFCConnectionStateClosed:
274-
[self.delegate didDisconnectNFC:self error:self.nfcConnectionError];
301+
if (previousState == YKFNFCConnectionStateOpen) {
302+
[self.delegate didDisconnectNFC:self error:self.nfcConnectionError];
303+
} else {
304+
[self.delegate didFailConnectingNFC:self.nfcConnectionError];
305+
}
275306
self.connectionController = nil;
276307
self.tagDescription = nil;
277308

278309
[self unobserveIso7816TagAvailability];
279310

280311
// invalidating session closes nfc reading sheet
281-
[self.nfcTagReaderSession invalidateSession];
312+
if (errorMessage) {
313+
[self.nfcTagReaderSession invalidateSessionWithErrorMessage:errorMessage];
314+
} else {
315+
[self.nfcTagReaderSession invalidateSession];
316+
}
282317
self.nfcTagReaderSession = nil;
283318
break;
284319

@@ -301,7 +336,6 @@ - (void)updateServicesForSession:(NFCTagReaderSession *)session tag:(id<NFCISO78
301336
break;
302337
}
303338

304-
self.nfcConnectionState = state;
305339
}
306340

307341
#pragma mark - Tag availability observation
@@ -318,7 +352,7 @@ - (void)observeIso7816TagAvailability API_AVAILABLE(ios(13.0)) {
318352
} else {
319353
YKFLogInfo(@"NFC tag is no longer available.");
320354
// moving from state of open back to polling/waiting for new tag
321-
[strongSelf updateServicesForSession:strongSelf.nfcTagReaderSession tag:nil state:YKFNFCConnectionStatePolling];
355+
[strongSelf updateServicesForSession:strongSelf.nfcTagReaderSession tag:nil state:YKFNFCConnectionStatePolling errorMessage:nil];
322356
}
323357
}];
324358
[[NSRunLoop mainRunLoop] addTimer:self.iso7816NfcTagAvailabilityTimer forMode:NSDefaultRunLoopMode];

0 commit comments

Comments
 (0)