Skip to content

Commit

Permalink
Restructured device info and config. Implemented nfc restricted, chal…
Browse files Browse the repository at this point in the history
…lenge response timeout and auto eject timeout.
  • Loading branch information
jensutbult committed Jun 4, 2024
1 parent 8e19aee commit 88240b9
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#import "YKFManagementDeviceInfo+Private.h"
#import "YKFNSMutableDataAdditions.h"
#import "YKFAssert.h"
#import "YKFNSDataAdditions+Private.h"

@implementation YKFManagementWriteAPDU

Expand All @@ -35,6 +36,18 @@ - (instancetype)initWithConfiguration:(nonnull YKFManagementInterfaceConfigurati
[configData ykf_appendByte:0];
}

if (configuration.autoEjectTimeout != 0) {
[configData ykf_appendUInt16EntryWithTag:YKFManagementTagAutoEjectTimeout value:configuration.autoEjectTimeout];
}

if (configuration.challengeResponseTimeout != 0) {
[configData ykf_appendUInt8EntryWithTag:YKFManagementTagChallengeResponseTimeout value:configuration.challengeResponseTimeout];
}

if (configuration.isNFCRestricted) {
[configData ykf_appendShortWithTag:YKFManagementTagNFCRestricted data:0x01];
}

NSMutableData *rawRequest = [[NSMutableData alloc] init];
[rawRequest ykf_appendByte:configData.length];
[rawRequest appendData:configData];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,14 @@

#import "YKFManagementInterfaceConfiguration.h"

@class YKFManagementDeviceInfo;
@class YKFManagementDeviceInfo, YKFTLVRecord;

@interface YKFManagementInterfaceConfiguration()

@property (nonatomic, readonly) NSUInteger usbSupportedMask;
@property (nonatomic, readonly) NSUInteger nfcSupportedMask;

@property (nonatomic, readonly) NSUInteger usbEnabledMask;
@property (nonatomic, readonly) NSUInteger nfcEnabledMask;

@property (nonatomic, readonly) BOOL usbMaskChanged;
@property (nonatomic, readonly) BOOL nfcMaskChanged;

- (nullable instancetype)initWithDeviceInfo:(nonnull YKFManagementDeviceInfo *)response NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithTLVRecords:(nonnull NSMutableArray<YKFTLVRecord*> *)records NS_DESIGNATED_INITIALIZER;

+ (NSUInteger)translateFipsMask:(NSUInteger)mask;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ typedef NS_ENUM(NSUInteger, YKFManagementTransportType) {
@interface YKFManagementInterfaceConfiguration : NSObject

@property (nonatomic, readonly) BOOL isConfigurationLocked;
@property (nonatomic, readwrite) NSTimeInterval autoEjectTimeout;
@property (nonatomic, readwrite) NSTimeInterval challengeResponseTimeout;
@property (nonatomic, readwrite) BOOL isNFCRestricted;

@property (nonatomic, readonly) NSUInteger usbSupportedMask;
@property (nonatomic, readonly) NSUInteger nfcSupportedMask;
@property (nonatomic, readwrite) NSUInteger usbEnabledMask;
@property (nonatomic, readwrite) NSUInteger nfcEnabledMask;

- (BOOL)isEnabled:(YKFManagementApplicationType)application overTransport:(YKFManagementTransportType)transport;
- (BOOL)isSupported:(YKFManagementApplicationType)application overTransport:(YKFManagementTransportType)transport;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,45 @@
#import "YKFManagementDeviceInfo+Private.h"
#import "YKFManagementDeviceInfo.h"
#import "YKFAssert.h"
#import "YKFTLVRecord.h"
#import "NSArray+YKFTLVRecord.h"
#import "YKFNSDataAdditions+Private.h"

@interface YKFManagementInterfaceConfiguration()

@property (nonatomic, readwrite) BOOL isConfigurationLocked;

@property (nonatomic, readwrite) NSUInteger usbSupportedMask;
@property (nonatomic, readwrite) NSUInteger nfcSupportedMask;

@property (nonatomic, readwrite) NSUInteger usbEnabledMask;
@property (nonatomic, readwrite) NSUInteger nfcEnabledMask;

@property (nonatomic, readwrite) BOOL usbMaskChanged;
@property (nonatomic, readwrite) BOOL nfcMaskChanged;

@end

@implementation YKFManagementInterfaceConfiguration

- (nullable instancetype)initWithDeviceInfo:(nonnull YKFManagementDeviceInfo *)deviceInfo {
YKFAssertAbortInit(deviceInfo);
- (nullable instancetype)initWithTLVRecords:(nonnull NSMutableArray<YKFTLVRecord*> *)records {
self = [super init];
if (self) {

self.isConfigurationLocked = deviceInfo.isConfigurationLocked;
self.usbSupportedMask = deviceInfo.usbSupportedMask;
self.nfcSupportedMask = deviceInfo.nfcSupportedMask;
self.usbEnabledMask = deviceInfo.usbEnabledMask;
self.nfcEnabledMask = deviceInfo.nfcEnabledMask;
self.isConfigurationLocked = [[records ykfTLVRecordWithTag:YKFManagementTagConfigLocked].value ykf_integerValue] == 1;
self.usbSupportedMask = [[records ykfTLVRecordWithTag:YKFManagementTagUSBSupported].value ykf_integerValue];
self.usbEnabledMask = [[records ykfTLVRecordWithTag:YKFManagementTagUSBEnabled].value ykf_integerValue];
self.nfcSupportedMask = [[records ykfTLVRecordWithTag:YKFManagementTagNFCSupported].value ykf_integerValue];
self.nfcEnabledMask = [[records ykfTLVRecordWithTag:YKFManagementTagNFCEnabled].value ykf_integerValue];

NSData *autoEjectTimeoutData = [records ykfTLVRecordWithTag:YKFManagementTagAutoEjectTimeout].value;
if (autoEjectTimeoutData) {
self.autoEjectTimeout = [autoEjectTimeoutData ykf_integerValue];
}

NSData *challengeResponseTimeoutData = [records ykfTLVRecordWithTag:YKFManagementTagChallengeResponseTimeout].value;
if (challengeResponseTimeoutData) {
self.challengeResponseTimeout = [challengeResponseTimeoutData ykf_integerValue];
}

NSData *isNFCRestrictedData = [records ykfTLVRecordWithTag:YKFManagementTagNFCRestricted].value;
if (isNFCRestrictedData) {
self.isNFCRestricted = [isNFCRestrictedData ykf_integerValue] == 1;
}
}
return self;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ - (void)getDeviceInfoWithCompletion:(YKFManagementSessionGetDeviceInfoBlock)comp
completion(nil, error);
return;
}
YKFManagementDeviceInfo *deviceInfo = [[YKFManagementDeviceInfo alloc] initWithResponseData:result defaultVersion:self.version];
YKFManagementDeviceInfo *deviceInfo = [[YKFManagementDeviceInfo alloc] initWithTLVRecords:result defaultVersion:self.version];
completion(deviceInfo, error);
return;
} result: [NSMutableArray<YKFTLVRecord *> new] page: 0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
@class YKFTLVRecord;
@interface YKFManagementDeviceInfo()

@property (nonatomic, readwrite) NSUInteger usbSupportedMask;
@property (nonatomic, readwrite) NSUInteger nfcSupportedMask;

@property (nonatomic, readwrite) NSUInteger usbEnabledMask;
@property (nonatomic, readwrite) NSUInteger nfcEnabledMask;

- (nullable instancetype)initWithResponseData:(NSMutableArray<YKFTLVRecord*> *)records defaultVersion:(YKFVersion *)defaultVersion NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithTLVRecords:(NSMutableArray<YKFTLVRecord*> *)records defaultVersion:(YKFVersion *)defaultVersion NS_DESIGNATED_INITIALIZER;

- (instancetype)init NS_UNAVAILABLE;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ @interface YKFManagementDeviceInfo()

@implementation YKFManagementDeviceInfo

- (nullable instancetype)initWithResponseData:(nonnull NSMutableArray<YKFTLVRecord*> *)records defaultVersion:(nonnull YKFVersion *)defaultVersion {
- (nullable instancetype)initWithTLVRecords:(nonnull NSMutableArray<YKFTLVRecord*> *)records defaultVersion:(nonnull YKFVersion *)defaultVersion {
YKFAssertAbortInit(records.count > 0);
YKFAssertAbortInit(defaultVersion)
self = [super init];
Expand Down Expand Up @@ -98,28 +98,23 @@ - (nullable instancetype)initWithResponseData:(nonnull NSMutableArray<YKFTLVReco
NSData *fpsVersionData = [records ykfTLVRecordWithTag:YKFManagementTagFPSVersion].value;
if (fpsVersionData) {
YKFVersion *version = [[YKFVersion alloc] initWithData:fpsVersionData];
if (version && version != [[YKFVersion alloc] initWithString:@"0.0.0"]) {
if (version && [version compare:[[YKFVersion alloc] initWithString:@"0.0.0"]] != NSOrderedSame) {
self.fpsVersion = version;
}
}
NSData *stmVersionData = [records ykfTLVRecordWithTag:YKFManagementTagSTMVersion].value;
if (stmVersionData) {
YKFVersion *version = [[YKFVersion alloc] initWithData:stmVersionData];
if (version && version != [[YKFVersion alloc] initWithString:@"0.0.0"]) {
if (version && [version compare:[[YKFVersion alloc] initWithString:@"0.0.0"]] != NSOrderedSame) {
self.stmVersion = version;
}
}
self.partNumber = [[NSString alloc] initWithData:[records ykfTLVRecordWithTag:YKFManagementTagSTMVersion].value encoding:NSUTF8StringEncoding];
self.partNumber = [[NSString alloc] initWithData:[records ykfTLVRecordWithTag:YKFManagementTagPartNumber].value encoding:NSUTF8StringEncoding];
if (self.partNumber.length == 0) {
self.partNumber = nil;
}

self.usbSupportedMask = [[records ykfTLVRecordWithTag:YKFManagementTagUSBSupported].value ykf_integerValue];
self.usbEnabledMask = [[records ykfTLVRecordWithTag:YKFManagementTagUSBEnabled].value ykf_integerValue];
self.nfcSupportedMask = [[records ykfTLVRecordWithTag:YKFManagementTagNFCSupported].value ykf_integerValue];
self.nfcEnabledMask = [[records ykfTLVRecordWithTag:YKFManagementTagNFCEnabled].value ykf_integerValue];

self.configuration = [[YKFManagementInterfaceConfiguration alloc] initWithDeviceInfo:self];
self.configuration = [[YKFManagementInterfaceConfiguration alloc] initWithTLVRecords:records];
}
return self;
}
Expand Down
10 changes: 10 additions & 0 deletions YubiKit/YubiKit/Helpers/Additions/YKFNSMutableDataAdditions.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ Appends [tag] + 0x02 + 2 bytes to the mutable data buffer.
*/
- (void)ykf_appendEntryWithTag:(UInt8)tag headerBytes:(NSArray *)headerBytes data:(NSData *)data;

/*
Appends the UInt8 value to the mutable data
*/
- (void)ykf_appendUInt8EntryWithTag:(UInt8)tag value:(UInt8)value;

/*
Appends the UInt16 value to the mutable data after converting it to a big endian represetation (key representation).
*/
- (void)ykf_appendUInt16EntryWithTag:(UInt8)tag value:(UInt16)value;

/*
Appends the UInt32 value to the mutable data after converting it to a big endian represetation (key representation).
*/
Expand Down
17 changes: 17 additions & 0 deletions YubiKit/YubiKit/Helpers/Additions/YKFNSMutableDataAdditions.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,23 @@ - (void)ykf_appendEntryWithTag:(UInt8)tag headerBytes:(NSArray *)headerBytes dat
[self ykf_appendEntryWithTag:tag data:buffer];
}

- (void)ykf_appendUInt8EntryWithTag:(UInt8)tag value:(UInt8)value {
YKFParameterAssertReturn(tag > 0);
[self ykf_appendByte:tag];
[self ykf_appendByte:sizeof(UInt8)];
[self appendBytes:&value length:sizeof(UInt8)];
}

- (void)ykf_appendUInt16EntryWithTag:(UInt8)tag value:(UInt16)value {
YKFParameterAssertReturn(tag > 0);

UInt16 bigEndianValue = CFSwapInt16HostToBig(value);

[self ykf_appendByte:tag];
[self ykf_appendByte:sizeof(UInt16)];
[self appendBytes:&bigEndianValue length:sizeof(UInt16)];
}

- (void)ykf_appendUInt32EntryWithTag:(UInt8)tag value:(UInt32)value {
YKFParameterAssertReturn(tag > 0);

Expand Down
38 changes: 34 additions & 4 deletions YubiKitTests/Tests/ManagementTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,45 @@ class ManagementTests: XCTestCase {
session.getDeviceInfo { deviceInfo, error in
guard let deviceInfo = deviceInfo else { XCTFail("Failed to get DeviceInfo: \(error!)"); return }
print("✅ Got device info:")
print(" is locked: \(deviceInfo.isConfigurationLocked)")
print(" serial number: \(deviceInfo.serialNumber)")
print(" form factor: \(deviceInfo.formFactor.rawValue)")
print(" firmware version: \(deviceInfo.version)")
print("""
YubiKey \(deviceInfo.formFactor) \(deviceInfo.version) (#\(deviceInfo.serialNumber))
Supported capabilities: \(String(describing: deviceInfo.configuration?.nfcSupportedMask))
Supported capabilities: \(String(describing: deviceInfo.configuration?.usbSupportedMask))
isConfigLocked: \(deviceInfo.isConfigurationLocked)
isFips: \(deviceInfo.isFips)
isSky: \(deviceInfo.isSky)
partNumber: \(String(describing: deviceInfo.partNumber))
isFipsCapable: \(deviceInfo.isFIPSCapable)
isFipsApproved: \(deviceInfo.isFIPSApproved)
pinComplexity: \(deviceInfo.pinComplexity)
resetBlocked: \(deviceInfo.isResetBlocked)
fpsVersion: \(String(describing: deviceInfo.fpsVersion))
stmVersion: \(String(describing: deviceInfo.stmVersion))
""")
completion()
}
}
}
}

func testZEnableNFCRestriction() {
runYubiKitTest { connection, completion in
connection.managementSessionAndDeviceInfo { session, deviceInfo in
guard let config = deviceInfo.configuration else { completion(); return }
config.isNFCRestricted = true
session.write(config, reboot: false) { error in
XCTAssertNil(error)
session.getDeviceInfo { deviceInfo, error in
XCTAssertNil(error)
if let isNFCRestricted = deviceInfo?.configuration?.isNFCRestricted {
XCTAssertTrue(isNFCRestricted)
}
completion()
}
}
}
}
}
}

extension YKFConnectionProtocol {
Expand Down

0 comments on commit 88240b9

Please sign in to comment.