-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1ea9c97
commit f59d42c
Showing
1 changed file
with
63 additions
and
181 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,56 +37,45 @@ class FIDO2DemoViewController: OtherDemoRootViewController { | |
private var selectedOperation: DemoName? | ||
private var pin: String? | ||
private var newPin: String? | ||
// MARK: - Actions | ||
|
||
private func runDemo() {} | ||
/* | ||
let keyPluggedIn = YubiKitManager.shared.accessorySession.connectionState == .open | ||
let fido2Service: YKFFIDO2SessionProtocol | ||
if YubiKitDeviceCapabilities.supportsISO7816NFCTags && !keyPluggedIn { | ||
guard #available(iOS 13.0, *) else { | ||
fatalError() | ||
} | ||
guard let service = YubiKitManager.shared.nfcSession.fido2Service else { | ||
log(message: "The session with the key is closed. Plugin the key or tap over NFC reader.") | ||
YubiKitManager.shared.nfcSession.start() | ||
return | ||
} | ||
fido2Service = service | ||
} else { | ||
guard let service = YubiKitManager.shared.accessorySession.fido2Service else { | ||
setDemoButtons(enabled: true) | ||
log(message: "The session with the key is closed. Plugin the key before running the demo.") | ||
return | ||
} | ||
fido2Service = service | ||
} | ||
// MARK: - Actions | ||
private func runDemo() { | ||
|
||
switch selectedOperation { | ||
case .GetInfo: | ||
runGetInfoDemo(fido2Service: fido2Service) | ||
case .EccDemo: | ||
runECCDemo(fido2Service: fido2Service) | ||
case .EdDSADemo: | ||
runEdDSADemo(fido2Service: fido2Service) | ||
case .Reset: | ||
runApplicationReset(fido2Service: fido2Service) | ||
case .PinVerify: | ||
verify(fido2Service: fido2Service, pin: pin!) | ||
case .PinSet: | ||
set(fido2Service: fido2Service, pin: pin!) | ||
case .PinChange: | ||
change(fido2Service: fido2Service, to: newPin!, oldPin: pin!) | ||
default: | ||
break | ||
self.connection { connection in | ||
connection.fido2Session { session, error in | ||
guard let session else { | ||
self.log(message: "Failed to establish FIDO2 session: \((error! as NSError).code) - \(error!.localizedDescription)") | ||
self.setDemoButtons(enabled: true) | ||
return | ||
} | ||
|
||
switch self.selectedOperation { | ||
case .GetInfo: | ||
self.runGetInfoDemo(fido2Session: session) | ||
case .EccDemo: | ||
self.runECCDemo(fido2Session: session) | ||
case .EdDSADemo: | ||
self.runEdDSADemo(fido2Session: session) | ||
case .Reset: | ||
self.runApplicationReset(fido2Session: session) | ||
case .PinVerify: | ||
self.verify(fido2Session: session, pin: self.pin!) | ||
case .PinSet: | ||
self.set(fido2Session: session, pin: self.pin!) | ||
case .PinChange: | ||
self.change(fido2Session: session, to: self.newPin!, oldPin: self.pin!) | ||
default: | ||
break | ||
} | ||
} | ||
} | ||
} | ||
|
||
private func finishDemo() { | ||
|
||
// Stop the session to dismiss the Core NFC system UI. | ||
if #available(iOS 13.0, *) { | ||
YubiKitManager.shared.nfcSession.stop() | ||
YubiKitManager.shared.stopNFCConnection() | ||
} | ||
|
||
self.setDemoButtons(enabled: true) | ||
|
@@ -199,11 +188,8 @@ class FIDO2DemoViewController: OtherDemoRootViewController { | |
} | ||
} | ||
|
||
private func verify(fido2Service: YKFFIDO2SessionProtocol, pin: String) { | ||
fido2Service.executeGetPinRetries { [weak self] (retries, error) in | ||
guard let self = self else { | ||
return | ||
} | ||
private func verify(fido2Session: YKFFIDO2Session, pin: String) { | ||
fido2Session.getPinRetries { retries, error in | ||
guard error == nil else { | ||
self.log(message: "Error while executing Get PIN Retries: \((error! as NSError).code) - \(error!.localizedDescription)") | ||
self.setDemoButtons(enabled: true) | ||
|
@@ -215,21 +201,14 @@ class FIDO2DemoViewController: OtherDemoRootViewController { | |
return | ||
} | ||
self.log(message: "PIN retries left: \(retries)") | ||
guard let verifyPinRequest = YKFFIDO2VerifyPinRequest(pin: pin) else { | ||
return | ||
} | ||
fido2Service.execute(verifyPinRequest) { [weak self] (error) in | ||
guard let self = self else { | ||
return | ||
} | ||
self.finishDemo() | ||
|
||
fido2Session.verifyPin(pin) { error in | ||
guard error == nil else { | ||
self.log(message: "Error while executing Verify PIN request: \((error! as NSError).code) - \(error!.localizedDescription)") | ||
self.setDemoButtons(enabled: true) | ||
return | ||
} | ||
self.setDemoButtons(enabled: true) | ||
self.log(message: "Verify PIN request was successful.") | ||
} | ||
} | ||
|
@@ -259,15 +238,8 @@ class FIDO2DemoViewController: OtherDemoRootViewController { | |
} | ||
} | ||
|
||
private func set(fido2Service: YKFFIDO2SessionProtocol, pin: String) { | ||
guard let setPinRequest = YKFFIDO2SetPinRequest(pin: pin) else { | ||
return | ||
} | ||
fido2Service.execute(setPinRequest) { [weak self] (error) in | ||
guard let self = self else { | ||
return | ||
} | ||
private func set(fido2Session: YKFFIDO2Session, pin: String) { | ||
fido2Session.setPin(pin) { error in | ||
self.finishDemo() | ||
|
||
guard error == nil else { | ||
|
@@ -305,16 +277,10 @@ class FIDO2DemoViewController: OtherDemoRootViewController { | |
} | ||
} | ||
|
||
private func change(fido2Service: YKFFIDO2SessionProtocol, to newPin: String, oldPin: String) { | ||
private func change(fido2Session: YKFFIDO2Session, to newPin: String, oldPin: String) { | ||
setDemoButtons(enabled: false) | ||
|
||
guard let changePinRequest = YKFFIDO2ChangePinRequest(newPin: newPin, oldPin: oldPin) else { | ||
return | ||
} | ||
fido2Service.execute(changePinRequest) { [weak self] (error) in | ||
guard let self = self else { | ||
return | ||
} | ||
fido2Session.changePin(oldPin, to: newPin) { error in | ||
|
||
self.finishDemo() | ||
|
||
|
@@ -329,14 +295,12 @@ class FIDO2DemoViewController: OtherDemoRootViewController { | |
|
||
// MARK: - GetInfo Demo | ||
|
||
private func runGetInfoDemo(fido2Service: YKFFIDO2SessionProtocol) { | ||
private func runGetInfoDemo(fido2Session: YKFFIDO2Session) { | ||
setDemoButtons(enabled: false) | ||
|
||
log(message: "Executing Get Info request...") | ||
fido2Service.executeGetInfoRequest { [weak self] (response, error) in | ||
guard let self = self else { | ||
return | ||
} | ||
|
||
fido2Session.getInfoWithCompletion { response, error in | ||
|
||
self.finishDemo() | ||
|
||
|
@@ -352,71 +316,59 @@ class FIDO2DemoViewController: OtherDemoRootViewController { | |
|
||
// MARK: - ES256, EdDSA Demos | ||
|
||
private func runECCDemo(fido2Service: YKFFIDO2SessionProtocol) { | ||
private func runECCDemo(fido2Session: YKFFIDO2Session) { | ||
setDemoButtons(enabled: false) | ||
|
||
log(message: "Executing ECC Demo...") | ||
log(message: "(!) Touch the key when the LEDs are blinking slowly.") | ||
|
||
// Not a resident key (stored on the authenticator) and no PIN required. | ||
let makeOptions = [YKFFIDO2MakeCredentialRequestOptionRK: false] | ||
let makeOptions = [YKFFIDO2OptionRK: false] | ||
|
||
// User presence required (touch) but not user verification (PIN). | ||
let assertionOptions = [YKFFIDO2GetAssertionRequestOptionUP: true] | ||
let assertionOptions = [YKFFIDO2OptionUP: true] | ||
|
||
makeFIDO2CredentialWith(fido2Service: fido2Service, algorithm:YKFFIDO2PublicKeyAlgorithmES256, makeOptions: makeOptions, assertionOptions: assertionOptions) | ||
makeFIDO2CredentialWith(fido2Session: fido2Session, algorithm:YKFFIDO2PublicKeyAlgorithmES256, makeOptions: makeOptions, assertionOptions: assertionOptions) | ||
} | ||
|
||
private func runEdDSADemo(fido2Service: YKFFIDO2SessionProtocol) { | ||
private func runEdDSADemo(fido2Session: YKFFIDO2Session) { | ||
setDemoButtons(enabled: false) | ||
|
||
log(message: "Executing EdDSA (Ed25519) Demo...") | ||
log(message: "(!) Touch the key when the LEDs are blinking slowly.") | ||
|
||
// Resident key (stored on the authenticator) and no PIN required. | ||
let makeOptions = [YKFFIDO2MakeCredentialRequestOptionRK: true] | ||
let makeOptions = [YKFFIDO2OptionRK: true] | ||
|
||
// User presence and verification disabled (silent authentication). | ||
let assertionOptions = [YKFFIDO2GetAssertionRequestOptionUP: false] | ||
let assertionOptions = [YKFFIDO2OptionUP: false] | ||
|
||
makeFIDO2CredentialWith(fido2Service: fido2Service, algorithm:YKFFIDO2PublicKeyAlgorithmEdDSA, makeOptions: makeOptions, assertionOptions: assertionOptions) | ||
makeFIDO2CredentialWith(fido2Session: fido2Session, algorithm:YKFFIDO2PublicKeyAlgorithmEdDSA, makeOptions: makeOptions, assertionOptions: assertionOptions) | ||
} | ||
|
||
private func makeFIDO2CredentialWith(fido2Service: YKFFIDO2SessionProtocol, algorithm: NSInteger, makeOptions: [String: Bool], assertionOptions: [String: Bool]) { | ||
private func makeFIDO2CredentialWith(fido2Session: YKFFIDO2Session, algorithm: NSInteger, makeOptions: [String: Bool], assertionOptions: [String: Bool]) { | ||
/* | ||
1. Setup the Make Credential request. | ||
*/ | ||
|
||
let makeCredentialRequest = YKFFIDO2MakeCredentialRequest() | ||
let data = Data(repeating: 0, count: 32) | ||
makeCredentialRequest.clientDataHash = data | ||
|
||
let rp = YKFFIDO2PublicKeyCredentialRpEntity() | ||
rp.rpId = "yubico.com" | ||
rp.rpName = "Yubico" | ||
makeCredentialRequest.rp = rp | ||
|
||
let user = YKFFIDO2PublicKeyCredentialUserEntity() | ||
user.userId = data | ||
user.userName = "[email protected]" | ||
user.userDisplayName = "John P. Smith" | ||
makeCredentialRequest.user = user | ||
|
||
let param = YKFFIDO2PublicKeyCredentialParam() | ||
param.alg = algorithm | ||
makeCredentialRequest.pubKeyCredParams = [param] | ||
makeCredentialRequest.options = makeOptions | ||
|
||
/* | ||
2. Create the credential. | ||
*/ | ||
fido2Service.execute(makeCredentialRequest) { [weak self] (response, error) in | ||
guard let self = self else { | ||
return | ||
} | ||
fido2Session.makeCredential(withClientDataHash: data, rp: rp, user: user, pubKeyCredParams: [param], excludeList: nil, options: makeOptions) { response, error in | ||
|
||
guard error == nil else { | ||
self.log(message: "Error while executing Make Credential request: \((error! as NSError).code) - \(error!.localizedDescription)") | ||
|
@@ -435,61 +387,41 @@ class FIDO2DemoViewController: OtherDemoRootViewController { | |
3. Setup the Get Assertion request. | ||
*/ | ||
|
||
let getAssertionRequest = YKFFIDO2GetAssertionRequest() | ||
getAssertionRequest.rpId = "yubico.com" | ||
getAssertionRequest.clientDataHash = data | ||
getAssertionRequest.options = assertionOptions | ||
let credentialDescriptor = YKFFIDO2PublicKeyCredentialDescriptor() | ||
credentialDescriptor.credentialId = authenticatorData.credentialId! | ||
let credType = YKFFIDO2PublicKeyCredentialType() | ||
credType.name = "public-key" | ||
credentialDescriptor.credentialType = credType | ||
getAssertionRequest.allowList = [credentialDescriptor] | ||
|
||
/* | ||
4. Get the assertion (signature). | ||
*/ | ||
|
||
self.getAssertionWith(fido2Service: fido2Service, request: getAssertionRequest) | ||
} | ||
} | ||
private func getAssertionWith(fido2Service: YKFFIDO2SessionProtocol, request: YKFFIDO2GetAssertionRequest) { | ||
fido2Service.execute(request) { [weak self] (response, error) in | ||
guard let self = self else { | ||
return | ||
} | ||
self.finishDemo() | ||
fido2Session.getAssertionWithClientDataHash(data, rpId: "yubico.com", allowList: [credentialDescriptor], options: assertionOptions) { response, error in | ||
self.finishDemo() | ||
|
||
guard error == nil else { | ||
self.log(message: "Error while executing Get Assertion request: \((error! as NSError).code) - \(error!.localizedDescription)") | ||
return | ||
guard error == nil else { | ||
self.log(message: "Error while executing Get Assertion request: \((error! as NSError).code) - \(error!.localizedDescription)") | ||
return | ||
} | ||
|
||
self.log(message: "Get Assertion was successful.\n") | ||
self.logFIDO2GetAssertion(response: response!) | ||
} | ||
self.log(message: "Get Assertion was successful.\n") | ||
self.logFIDO2GetAssertion(response: response!) | ||
} | ||
} | ||
|
||
// MARK: - FIDO2 Application Reset | ||
|
||
private func runApplicationReset(fido2Service: YKFFIDO2SessionProtocol) { | ||
private func runApplicationReset(fido2Session: YKFFIDO2Session) { | ||
setDemoButtons(enabled: false) | ||
|
||
log(message: "(!) The Reset operation must be executed within 5 seconds after the key was powered up. Otherwise the key will return an error.") | ||
log(message: "") | ||
log(message: "Executing Reset request...") | ||
log(message: "(!) Touch the key when the LEDs are blinking slowly.") | ||
|
||
fido2Service.executeResetRequest { [weak self] (error) in | ||
guard let self = self else { | ||
return | ||
} | ||
fido2Session.reset { error in | ||
|
||
self.finishDemo() | ||
|
||
|
@@ -502,55 +434,6 @@ class FIDO2DemoViewController: OtherDemoRootViewController { | |
} | ||
} | ||
|
||
// MARK: - Session State Updates | ||
override func accessorySessionStateDidChange() { | ||
let sessionState = YubiKitManager.shared.accessorySession.connectionState | ||
if sessionState == .closed { | ||
logTextView.text = nil | ||
setDemoButtons(enabled: true) | ||
} else if sessionState == .open { | ||
if YubiKitDeviceCapabilities.supportsISO7816NFCTags { | ||
guard #available(iOS 13.0, *) else { | ||
fatalError() | ||
} | ||
DispatchQueue.global(qos: .default).async { [weak self] in | ||
// if NFC UI is visible we consider the button is pressed | ||
// and we run demo as soon as 5ci connected | ||
if (YubiKitManager.shared.nfcSession.nfcConnectionState != .closed) { | ||
guard let self = self else { | ||
return | ||
} | ||
YubiKitManager.shared.nfcSession.stop() | ||
self.runDemo() | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@available(iOS 13.0, *) | ||
override func nfcSessionStateDidChange() { | ||
// Execute the request after the key(tag) is connected. | ||
switch YubiKitManager.shared.nfcSession.nfcConnectionState { | ||
case .open: | ||
DispatchQueue.global(qos: .default).async { [weak self] in | ||
guard let self = self else { | ||
return | ||
} | ||
// NOTE: session can be closed during the execution of demo on background thread, | ||
// so we need to make sure that we handle case when service for nfcSession is nil | ||
self.runDemo() | ||
} | ||
case .closed: | ||
self.setDemoButtons(enabled: true) | ||
default: | ||
break | ||
} | ||
} | ||
// MARK: - FIDO2 Response Log Helpers | ||
|
||
private func logFIDO2GetInfo(response: YKFFIDO2GetInfoResponse) { | ||
|
@@ -647,5 +530,4 @@ class FIDO2DemoViewController: OtherDemoRootViewController { | |
private func log(tag: String, value: String) { | ||
log(message: "\n* \(tag):\n\(value)") | ||
} | ||
*/ | ||
} |