Last active
June 5, 2020 23:41
-
-
Save dmennis/e95f85e2d30e9e08672e2487282d549d to your computer and use it in GitHub Desktop.
Revisions
-
dmennis revised this gist
Jun 5, 2020 . 1 changed file with 17 additions and 10 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -9,13 +9,15 @@ // The app establishes an open NFC connection with the YubiKey, reads the credentials from the OATH module and retrieves a TOTP code based on the first OATH credential retrieved. // // There are three main NFC components to this class: // 1. StartNFC Session - Line 49 -> Triggered by a button click that starts the NFC reader session // 2. NFC Session (OBSERVER) - Line 66 -> Registers to receive callbacks sent from an NFC tag reader session. // 3. NFC Session (HANDLER) - Line 94 -> This handles callbacks when the NFC tag reader session detects an ISO 7816 tag // // The other two main functions are communicating with the OATH module of the YubiKey over the NFCReaderSession. // 1. getOATHCredentials() - Line 113 gets the list of all OATH credentials stored on that key // 2. getOTPCode() - Line 152 calls the YKFKeyOATHCalculateRequest which asks the YubiKey to generate a TOTP code for given credential // Updated Github Gist on June 5 here: https://gist.github.com/dmennis/e95f85e2d30e9e08672e2487282d549d import UIKit import YubiKit @@ -72,6 +74,7 @@ class ViewController: UIViewController { isNFCObservingSessionStateUpdates = newValue let nfcSession = YubiKitManager.shared.nfcSession as! YKFNFCSession if isNFCObservingSessionStateUpdates { self.nfcSesionStateObservation = nfcSession.observe(\.iso7816SessionState, changeHandler: { [weak self] session, change in DispatchQueue.main.async { [weak self] in @@ -134,15 +137,19 @@ class ViewController: UIViewController { self.lblCode.text = "\(credCount) credentials found." } // Get the first YKFOATHCredential from the list of YKFOATHCredential's, if not empty if(!credentials.isEmpty) { let credential = credentials.first as! YKFOATHCredential self.getOTPCode(oathCredential: credential) } else { // Nothing to calculate, close the NFC session. YubiKitManager.shared.nfcSession.stopIso7816Session() } } } // Ask YubiKey for the TOTP of the provided OATH credential func getOTPCode(oathCredential: YKFOATHCredential) { // Create the CALCULATE request guard let calculateRequest = YKFKeyOATHCalculateRequest(credential: oathCredential) else { return } -
dmennis revised this gist
Jun 5, 2020 . 1 changed file with 5 additions and 5 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -9,13 +9,13 @@ // The app establishes an open NFC connection with the YubiKey, reads the credentials from the OATH module and retrieves a TOTP code based on the first OATH credential retrieved. // // There are three main NFC components to this class: // 1. StartNFC Session - Line 47 -> Triggered by a button click that starts the NFC reader session // 2. NFC Session (OBSERVER) - Line 64 -> Registers to receive callbacks sent from an NFC tag reader session. // 3. NFC Session (HANDLER) - Line 91 -> This handles callbacks when the NFC tag reader session detects an ISO 7816 tag // // The other two main functions are communicating with the OATH module of the YubiKey over the NFCReaderSession. // 1. getOATHCredentials() - Line 110 gets the list of all OATH credentials stored on that key // 2. getOTPCode() - Line 142 calls the YKFKeyOATHCalculateRequest which asks the YubiKey to generate a TOTP code for given credential import UIKit import YubiKit -
dmennis created this gist
Jun 5, 2020 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,191 @@ // // ViewController.swift // OATH-NFC // // Created by Dennis Hills on 6/5/20. // Copyright © 2020 Dennis Hills. All rights reserved. // // Description: This is sample app demonstrating NFC interaction with the OATH module of a YubiKey using the Yubico iOS SDK // The app establishes an open NFC connection with the YubiKey, reads the credentials from the OATH module and retrieves a TOTP code based on the first OATH credential retrieved. // // There are three main NFC components to this class: // 1. StartNFC Session - Line 41 -> Triggered by a button click that starts the NFC reader session // 2. NFC Session (OBSERVER) - Line 57 -> Registers to receive callbacks sent from an NFC tag reader session. // 3. NFC Session (HANDLER) - Line 85 -> This handles callbacks when the NFC tag reader session detects an ISO 7816 tag // // The other two main functions are communicating with the OATH module of the YubiKey over the NFCReaderSession. // 1. getOATHCredentials() - Line 105 gets the list of all OATH credentials stored on that key // 2. getOTPCode() - Line 138 calls the YKFKeyOATHCalculateRequest which asks the YubiKey to generate a TOTP code for given credential import UIKit import YubiKit class ViewController: UIViewController { // UI Stuff @IBOutlet weak var btnStartNFC: UIButton! // Tap this button to start the NFC Session @IBOutlet weak var lblCode: UILabel! // Displays the TOTP code // NFC Session observation private var isNFCObservingSessionStateUpdates = false private var nfcSesionStateObservation: NSKeyValueObservation? var oathService: YKFKeyOATHServiceProtocol? = nil override func viewWillAppear(_ animated: Bool) { if (YubiKitDeviceCapabilities.supportsISO7816NFCTags) { guard #available(iOS 13.0, *) else { fatalError() } observeNFCSessionStateUpdates = true } } override func viewDidLoad() { super.viewDidLoad() } // Initiates the NFCTagReaderSession for interfacing with an ISO 7816 tag @IBAction func startNFCSession(_ sender: Any) { guard #available(iOS 13.0, *) else { fatalError() } if YubiKitDeviceCapabilities.supportsISO7816NFCTags { if YubiKitManager.shared.nfcSession.iso7816SessionState != .closed { YubiKitManager.shared.nfcSession.stopIso7816Session() } YubiKitManager.shared.nfcSession.startIso7816Session() } } /******************** NFC Session Observer ********************/ @available(iOS 13.0, *) var observeNFCSessionStateUpdates: Bool { get { return isNFCObservingSessionStateUpdates } set { guard newValue != isNFCObservingSessionStateUpdates else { return } isNFCObservingSessionStateUpdates = newValue let nfcSession = YubiKitManager.shared.nfcSession as! YKFNFCSession if isNFCObservingSessionStateUpdates { self.nfcSesionStateObservation = nfcSession.observe(\.iso7816SessionState, changeHandler: { [weak self] session, change in DispatchQueue.main.async { [weak self] in self?.nfcSessionStateDidChange() } }) } else { self.nfcSesionStateObservation = nil } } } /******************* NFC Session Handler ********************/ @available(iOS 13.0, *) func nfcSessionStateDidChange() { switch YubiKitManager.shared.nfcSession.iso7816SessionState { case .open: DispatchQueue.global(qos: .default).async { [weak self] in if (YubiKitManager.shared.nfcSession.iso7816SessionState != .closed) { guard let self = self else { return } // Take action here to begin communicating with the YubiKey self.getOATHCredentials() } } case .closed: break default: break } } // Get the list of OATH credentials from the OATH module over the open NFC session // This is called by nfcSessionStateDidChange() when the NFCSession is active and open func getOATHCredentials() { var credCount: Int = 0 // Using the oathService instance over the open NFC session oathService = YubiKitManager.shared.nfcSession.oathService oathService?.executeListRequest { (response, error) in guard error == nil else { print("The list request ended in error \(error!.localizedDescription)") return } // If the error is nil, the response cannot be empty. guard response != nil else { print("Error in getting list of OATH credentials: \(String(describing: response))") fatalError() } let credentials = response!.credentials credCount = credentials.count print("The key has \(credentials.count) stored credentials.") DispatchQueue.main.async { self.lblCode.text = "\(credCount) credentials found." } self.getOTPCode(oathCredentials: credentials ) } } // Ask YubiKey for the TOTP of the provided OATH credential func getOTPCode(oathCredentials: [Any]) { // Get the first YKFOATHCredential from the list of YKFOATHCredential's let oathCredential = oathCredentials.first as! YKFOATHCredential // Create the CALCULATE request guard let calculateRequest = YKFKeyOATHCalculateRequest(credential: oathCredential) else { return } // Initialize the OATH Service oathService = YubiKitManager.shared.nfcSession.oathService // Execute the calculateRequest oathService?.execute(calculateRequest) { (response, error) in guard error == nil else { print("The calculateRequest ended in error: \(error!.localizedDescription)") return } // If the error is nil, the response cannot be empty. guard response != nil else { fatalError() } // Retrieve the generated TOTP code let otp = response!.otp print("The OTP value for credential [\(String(describing: oathCredential.label))] is \(otp)") // Display the TOTP code DispatchQueue.main.async { self.lblCode.text = "\(otp)" } // Done calculting, close the NFC session. YubiKitManager.shared.nfcSession.stopIso7816Session() } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if (YubiKitDeviceCapabilities.supportsISO7816NFCTags) { guard #available(iOS 13.0, *) else { fatalError() } observeNFCSessionStateUpdates = false } } deinit { if #available(iOS 13.0, *) { observeNFCSessionStateUpdates = false } } }