Skip to content

Commit

Permalink
Fixed broken FIDO2 demo app.
Browse files Browse the repository at this point in the history
  • Loading branch information
jensutbult committed Aug 15, 2024
1 parent 1ea9c97 commit f59d42c
Showing 1 changed file with 63 additions and 181 deletions.
244 changes: 63 additions & 181 deletions YubiKitDemo/YubiKitDemo/Demos/Other/Demos/FIDO2DemoViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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.")
}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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()

Expand All @@ -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()

Expand All @@ -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)")
Expand All @@ -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()

Expand All @@ -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) {
Expand Down Expand Up @@ -647,5 +530,4 @@ class FIDO2DemoViewController: OtherDemoRootViewController {
private func log(tag: String, value: String) {
log(message: "\n* \(tag):\n\(value)")
}
*/
}

0 comments on commit f59d42c

Please sign in to comment.