From 97be035c3ab458ab32a9af99d778d1ffc3b1ebc5 Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Mon, 12 Mar 2018 16:04:17 -0600 Subject: [PATCH 1/5] global counter stored as keychain password Fixes #47. Apple seems to have broken the SecItemUpdate API, which we were using to update the counter we were storing the the applicationTag. --- SoftU2F.xcodeproj/project.pbxproj | 16 +++- SoftU2FTool/CLI.swift | 2 - SoftU2FTool/Counter.swift | 88 +++++++++++++++++++++ SoftU2FTool/Mutex.swift | 21 +++++ SoftU2FTool/U2FAuthenticator.swift | 6 +- SoftU2FTool/U2FRegistration.swift | 63 ++------------- SoftU2FTool/UserPresence.swift | 14 ++-- SoftU2FToolTests/CounterTests.swift | 44 +++++++++++ SoftU2FToolTests/U2FRegistrationTests.swift | 21 ----- 9 files changed, 184 insertions(+), 91 deletions(-) create mode 100644 SoftU2FTool/Counter.swift create mode 100644 SoftU2FTool/Mutex.swift create mode 100644 SoftU2FToolTests/CounterTests.swift diff --git a/SoftU2F.xcodeproj/project.pbxproj b/SoftU2F.xcodeproj/project.pbxproj index 0123c0e..ae6356e 100644 --- a/SoftU2F.xcodeproj/project.pbxproj +++ b/SoftU2F.xcodeproj/project.pbxproj @@ -85,6 +85,9 @@ F738F5871E4A3C09005680A2 /* DataReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5851E4A3C09005680A2 /* DataReaderTests.swift */; }; F738F5881E4A3C09005680A2 /* DataWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5861E4A3C09005680A2 /* DataWriterTests.swift */; }; F738F58A1E4A3C21005680A2 /* TestUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5891E4A3C21005680A2 /* TestUtil.swift */; }; + F761094D2056FE3F006BB8B0 /* Counter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761094C2056FE3F006BB8B0 /* Counter.swift */; }; + F761094F2057198A006BB8B0 /* CounterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761094E2057198A006BB8B0 /* CounterTests.swift */; }; + F761095120572117006BB8B0 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761095020572117006BB8B0 /* Mutex.swift */; }; F7713A5F1F477BA90036A0D5 /* CLI.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7713A5D1F477BA90036A0D5 /* CLI.swift */; }; F7713A601F477BA90036A0D5 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7713A5E1F477BA90036A0D5 /* Settings.swift */; }; F7ABD9BE1E80603D00768FEC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F7ABD9BD1E80603D00768FEC /* Assets.xcassets */; }; @@ -243,6 +246,9 @@ F738F5851E4A3C09005680A2 /* DataReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataReaderTests.swift; path = DataTests/DataReaderTests.swift; sourceTree = ""; }; F738F5861E4A3C09005680A2 /* DataWriterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataWriterTests.swift; path = DataTests/DataWriterTests.swift; sourceTree = ""; }; F738F5891E4A3C21005680A2 /* TestUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUtil.swift; sourceTree = ""; }; + F761094C2056FE3F006BB8B0 /* Counter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Counter.swift; sourceTree = ""; }; + F761094E2057198A006BB8B0 /* CounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CounterTests.swift; sourceTree = ""; }; + F761095020572117006BB8B0 /* Mutex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = ""; }; F7713A5D1F477BA90036A0D5 /* CLI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLI.swift; sourceTree = ""; }; F7713A5E1F477BA90036A0D5 /* Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; F7ABD9BD1E80603D00768FEC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -374,6 +380,8 @@ 5119862D1E3C1519006A3BBB /* KnownFacets.swift */, 514F3D811E43C833008FA513 /* Keychain.swift */, 514F3D861E43E828008FA513 /* KeyPair.swift */, + F761094C2056FE3F006BB8B0 /* Counter.swift */, + F761095020572117006BB8B0 /* Mutex.swift */, 51FE30F01E410B3D00BAE824 /* Utils.swift */, 51213EC51E3916EB005454E0 /* U2FHID.swift */, 51B289E41E39903F00AD90CC /* U2FAuthenticator.swift */, @@ -390,6 +398,7 @@ 51F090201E37E8C600F03AD3 /* SoftU2FTests */ = { isa = PBXGroup; children = ( + F761094E2057198A006BB8B0 /* CounterTests.swift */, 51FE30EE1E40F3DB00BAE824 /* U2FRegistrationTests.swift */, 51E2145D1E3823E0005B2864 /* SHA256Tests.swift */, 51203C381E39234000F661DF /* U2FHIDTests.swift */, @@ -852,7 +861,9 @@ F7713A601F477BA90036A0D5 /* Settings.swift in Sources */, 5119862E1E3C1519006A3BBB /* KnownFacets.swift in Sources */, 51F090101E37E8C600F03AD3 /* AppDelegate.swift in Sources */, + F761095120572117006BB8B0 /* Mutex.swift in Sources */, 51213EC61E3916EB005454E0 /* U2FHID.swift in Sources */, + F761094D2056FE3F006BB8B0 /* Counter.swift in Sources */, 51E214601E3823E7005B2864 /* SHA256.swift in Sources */, 51B289E51E39903F00AD90CC /* U2FAuthenticator.swift in Sources */, 514F3D821E43C833008FA513 /* Keychain.swift in Sources */, @@ -867,6 +878,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F761094F2057198A006BB8B0 /* CounterTests.swift in Sources */, 51E214641E382529005B2864 /* WebSafeBase64Tests.swift in Sources */, 5131C1B01E3B9C62006A820C /* IntegrationTests.swift in Sources */, 51E2145E1E3823E0005B2864 /* SHA256Tests.swift in Sources */, @@ -1159,7 +1171,7 @@ HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/inc"; INFOPLIST_FILE = SoftU2FToolTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - LIBRARY_SEARCH_PATHS = "/usr/local/Cellar/libu2f-host/1.1.3/lib"; + LIBRARY_SEARCH_PATHS = "/usr/local/Cellar/libu2f-host/1.1.5/lib"; PRODUCT_BUNDLE_IDENTIFIER = com.github.SoftU2FToolTests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1182,7 +1194,7 @@ HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/inc"; INFOPLIST_FILE = SoftU2FToolTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - LIBRARY_SEARCH_PATHS = "/usr/local/Cellar/libu2f-host/1.1.3/lib"; + LIBRARY_SEARCH_PATHS = "/usr/local/Cellar/libu2f-host/1.1.5/lib"; PRODUCT_BUNDLE_IDENTIFIER = com.github.SoftU2FToolTests; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/SoftU2FTool/CLI.swift b/SoftU2FTool/CLI.swift index 1e4017a..bd1118e 100644 --- a/SoftU2FTool/CLI.swift +++ b/SoftU2FTool/CLI.swift @@ -53,7 +53,6 @@ class CLI { print(" - Key handle: This is the key handle that we registered with a website. For Soft U2F, the key handle is simply a hash of the public key.") print(" - Application parameter: This is the sha256 of the app-id of the site.") print(" - Known facet: For some sites we know the application parameter → site name mapping.") - print(" - Counter: How many times this registration has been used.") print(" — In SEP: Whether this registration's private key is stored in the SEP.") print("") @@ -67,7 +66,6 @@ class CLI { print("Known facet: N/A") } - print("Counter: ", reg.counter) print("In SEP: ", reg.inSEP) print("") } diff --git a/SoftU2FTool/Counter.swift b/SoftU2FTool/Counter.swift new file mode 100644 index 0000000..869e46a --- /dev/null +++ b/SoftU2FTool/Counter.swift @@ -0,0 +1,88 @@ +// +// Counter.swift +// SoftU2F +// +// Created by Benjamin P Toews on 3/12/18. +// + +import Foundation + +class Counter { + + private static let service = "Soft U2F" + private static let serviceLen = UInt32(service.utf8.count) + private static let account = "counter" + private static let accountLen = UInt32(account.utf8.count) + private static let mtx = Mutex() + + static var next: UInt32 { + mtx.lock() + defer { mtx.unlock() } + + let c = current ?? 0 + current = c + 1 + return c + } + + // assumes mtx is already locked + static var current: UInt32? { + get { + var valLen: UInt32 = 0 + var val: UnsafeMutableRawPointer? = nil + + let err = SecKeychainFindGenericPassword(nil, serviceLen, service, accountLen, account, &valLen, &val, nil) + if err != errSecSuccess { + if err != errSecItemNotFound { + print("Error from keychain: \(err)") + } + return nil + } + if val == nil { return nil } + defer { SecKeychainItemFreeContent(nil, val) } + + guard let strVal = NSString(bytes: val!, length: Int(valLen), encoding: String.Encoding.utf8.rawValue) as String? else { + return nil + } + + return UInt32(strVal) + } + + set { + let err: OSStatus + if let val: UInt32 = newValue { + let strVal = String(val) + let strValLen = UInt32(strVal.utf8.count) + if let it = item { + err = SecKeychainItemModifyContent(it, nil, strValLen, strVal) + } else { + err = SecKeychainAddGenericPassword(nil, serviceLen, service, accountLen, account, strValLen, strVal, nil) + } + } else { + if let it = item { + err = SecKeychainItemDelete(it) + } else { + return + } + } + + if err != errSecSuccess { + print("Error from keychain: \(err)") + } + } + } + + // assumes mtx is already locked + private static var item: SecKeychainItem? { + var it: SecKeychainItem? = nil + + let err = SecKeychainFindGenericPassword(nil, serviceLen, service, accountLen, account, nil, nil, &it) + if err != errSecSuccess { + if err != errSecItemNotFound { + print("Error from keychain: \(err)") + } + return nil + } + + return it + } +} diff --git a/SoftU2FTool/Mutex.swift b/SoftU2FTool/Mutex.swift new file mode 100644 index 0000000..0003a6d --- /dev/null +++ b/SoftU2FTool/Mutex.swift @@ -0,0 +1,21 @@ +// +// Mutex.swift +// SoftU2F +// +// Created by Benjamin P Toews on 3/12/18. +// Copyright © 2018 GitHub. All rights reserved. +// + +import Foundation + +class Mutex { + private var semaphore = DispatchSemaphore(value: 1) + + func lock() { + semaphore.wait() + } + + func unlock() { + semaphore.signal() + } +} diff --git a/SoftU2FTool/U2FAuthenticator.swift b/SoftU2FTool/U2FAuthenticator.swift index c749d37..6f92fd9 100644 --- a/SoftU2FTool/U2FAuthenticator.swift +++ b/SoftU2FTool/U2FAuthenticator.swift @@ -169,8 +169,8 @@ class U2FAuthenticator { return } - let counter = reg.counter - var ctrBigEndian = counter.bigEndian + let ctr = Counter.next + var ctrBigEndian = ctr.bigEndian let payloadSize = req.applicationParameter.count + 1 + MemoryLayout.size + req.challengeParameter.count var sigPayload = Data(capacity: payloadSize) @@ -185,7 +185,7 @@ class U2FAuthenticator { return } - let resp = AuthenticationResponse(userPresence: 0x01, counter: counter, signature: sig) + let resp = AuthenticationResponse(userPresence: 0x01, counter: ctr, signature: sig) self.sendMsg(msg: resp, cid: cid) return } diff --git a/SoftU2FTool/U2FRegistration.swift b/SoftU2FTool/U2FRegistration.swift index 07f4b0e..2c58997 100644 --- a/SoftU2FTool/U2FRegistration.swift +++ b/SoftU2FTool/U2FRegistration.swift @@ -44,7 +44,6 @@ class U2FRegistration { let keyPair: KeyPair let applicationParameter: Data - var counter: UInt32 // Key handle is application label plus 50 bytes of padding. Conformance tests require key handle to be >64 bytes. var keyHandle: Data { @@ -57,13 +56,12 @@ class U2FRegistration { // Generate a new registration. init?(applicationParameter ap: Data, inSEP sep: Bool) { - applicationParameter = ap - + // TODO Specify applicationTag during creation. Alternatively, detect if setting tag fails. guard let kp = KeyPair(label: U2FRegistration.namespace, inSEP: sep) else { return nil } + kp.applicationTag = ap + + applicationParameter = ap keyPair = kp - - counter = 1 - writeApplicationTag() } // Find a registration with the given key handle. @@ -78,19 +76,7 @@ class U2FRegistration { // Read our application parameter from the keychain and make sure it matches. guard let appTag = keyPair.applicationTag else { return nil } - - let counterSize = MemoryLayout.size - let appTagSize = Int(U2F_APPID_SIZE) - - if appTag.count != counterSize + appTagSize { - return nil - } - - counter = appTag.withUnsafeBytes { (ptr:UnsafePointer) -> UInt32 in - return ptr.pointee.bigEndian - } - - applicationParameter = appTag.subdata(in: counterSize..<(counterSize + appTagSize)) + applicationParameter = appTag if applicationParameter != ap { print("Bad applicationParameter") @@ -102,47 +88,12 @@ class U2FRegistration { init?(keyPair kp: KeyPair) { keyPair = kp - // Read our application parameter from the keychain. guard let appTag = keyPair.applicationTag else { return nil } - - let counterSize = MemoryLayout.size - let appTagSize = Int(U2F_APPID_SIZE) - - if appTag.count != counterSize + appTagSize { - return nil - } - - counter = appTag.withUnsafeBytes { (ptr:UnsafePointer) -> UInt32 in - return ptr.pointee.bigEndian - } - - applicationParameter = appTag.subdata(in: counterSize..<(counterSize + appTagSize)) + applicationParameter = appTag } // Sign some data with the private key and increment our counter. func sign(_ data: Data) -> Data? { - guard let sig = keyPair.sign(data) else { return nil } - - incrementCounter() - - return sig - } - - func incrementCounter() { - counter += 1 - writeApplicationTag() - } - - // Persist the applicationParameter and counter in the keychain. - func writeApplicationTag() { - let counterSize = MemoryLayout.size - let appTagSize = Int(U2F_APPID_SIZE) - var data = Data(capacity: counterSize + appTagSize) - var ctrBigEndian = counter.bigEndian - - data.append(Data(bytes: &ctrBigEndian, count: counterSize)) - data.append(applicationParameter) - - keyPair.applicationTag = data + return keyPair.sign(data) } } diff --git a/SoftU2FTool/UserPresence.swift b/SoftU2FTool/UserPresence.swift index 5e694eb..23fe8f0 100644 --- a/SoftU2FTool/UserPresence.swift +++ b/SoftU2FTool/UserPresence.swift @@ -18,19 +18,19 @@ class UserPresence: NSObject { static var skip = false // Hacks to avoid a race between reads/writes to current. - static let currentAccessQueue = DispatchQueue(label: "currentAccessQueue") + static let mtx = Mutex() static var _current: UserPresence? static var current: UserPresence? { get { - return currentAccessQueue.sync { - return _current - } + mtx.lock() + defer { mtx.unlock() } + return _current } set(newValue) { - currentAccessQueue.sync { - _current = newValue - } + mtx.lock() + defer { mtx.unlock() } + _current = newValue } } diff --git a/SoftU2FToolTests/CounterTests.swift b/SoftU2FToolTests/CounterTests.swift new file mode 100644 index 0000000..905ca5c --- /dev/null +++ b/SoftU2FToolTests/CounterTests.swift @@ -0,0 +1,44 @@ +// +// CounterTest.swift +// SoftU2FTests +// +// Created by Benjamin P Toews on 3/12/18. +// Copyright © 2018 GitHub. All rights reserved. +// + +import XCTest + +@testable import SoftU2F +class CounterTests: XCTestCase { + + override func setUp() { + super.setUp() + Counter.current = nil + } + + override func tearDown() { + Counter.current = nil + super.tearDown() + } + + func testCounterCurrent() { + XCTAssertEqual(nil, Counter.current) + + Counter.current = 123 + XCTAssertEqual(123, Counter.current) + + Counter.current = 234 + XCTAssertEqual(234, Counter.current) + + Counter.current = nil + XCTAssertEqual(nil, Counter.current) + } + + func testCounterNext() { + XCTAssertEqual(nil, Counter.current) + XCTAssertEqual(0, Counter.next) + XCTAssertEqual(1, Counter.next) + XCTAssertEqual(2, Counter.next) + XCTAssertEqual(3, Counter.current) + } +} diff --git a/SoftU2FToolTests/U2FRegistrationTests.swift b/SoftU2FToolTests/U2FRegistrationTests.swift index a46668b..e6cb8a8 100644 --- a/SoftU2FToolTests/U2FRegistrationTests.swift +++ b/SoftU2FToolTests/U2FRegistrationTests.swift @@ -111,25 +111,4 @@ class U2FRegistrationTests: SoftU2FTestCase { XCTAssertTrue(key.keyPair.verify(data: msg, signature: sig)) } - - func testCounterIncrementsAfterSign() { - let msg = "hello, world!".data(using: .utf8)! - - guard let key = makeKey else { - XCTFail("Couldn't make key") - return - } - - XCTAssertEqual(key.counter, 1) - XCTAssertEqual(key.counter, 1) - - for i in 2...6 { - guard let _ = key.sign(msg) else { - XCTFail("Couldn't sing data") - return - } - - XCTAssertEqual(key.counter, UInt32(i)) - } - } } From 27f490b4188f1bbf9851bf536da2f3ae307d989a Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Mon, 12 Mar 2018 16:23:57 -0600 Subject: [PATCH 2/5] repair existing registrations --- SoftU2FTool/U2FRegistration.swift | 34 ++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/SoftU2FTool/U2FRegistration.swift b/SoftU2FTool/U2FRegistration.swift index 2c58997..1df0c99 100644 --- a/SoftU2FTool/U2FRegistration.swift +++ b/SoftU2FTool/U2FRegistration.swift @@ -35,6 +35,38 @@ class U2FRegistration { // Fix up legacy keychain items. static func repair() { KeyPair.repair(label: namespace) + + let legacyCounterSize = MemoryLayout.size + let appTagSize = Int(U2F_APPID_SIZE) + var maxCtr = Counter.current ?? 0 + + for kp in KeyPair.all(label: namespace) { + guard let appTag = kp.applicationTag else { continue } + + switch appTag.count { + case appTagSize: + continue + case legacyCounterSize + appTagSize: + // Find the maximum legacy counter. + let ctr = appTag.withUnsafeBytes { (ptr:UnsafePointer) -> UInt32 in + return ptr.pointee.bigEndian + } + if ctr > maxCtr { + maxCtr = ctr + } + + // remove legacy counter from the application tag. + kp.applicationTag = appTag.subdata(in: legacyCounterSize..<(legacyCounterSize + appTagSize)) + default: + print("bad applicationTag size") + continue + } + } + + // Use the highest per-registration counter value as our global counter value. + if maxCtr > 0 { + Counter.current = maxCtr + } } // Delete all SoftU2F keys from keychain. @@ -59,7 +91,7 @@ class U2FRegistration { // TODO Specify applicationTag during creation. Alternatively, detect if setting tag fails. guard let kp = KeyPair(label: U2FRegistration.namespace, inSEP: sep) else { return nil } kp.applicationTag = ap - + applicationParameter = ap keyPair = kp } From 4142ae3edf20909297a33938e4d887afd07cf05d Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Tue, 13 Mar 2018 13:50:02 -0600 Subject: [PATCH 3/5] off by one People's counters have been stuck at X. Our first authentication shouldn't return X, but X+1. --- SoftU2FTool/U2FRegistration.swift | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/SoftU2FTool/U2FRegistration.swift b/SoftU2FTool/U2FRegistration.swift index 1df0c99..d0d62b1 100644 --- a/SoftU2FTool/U2FRegistration.swift +++ b/SoftU2FTool/U2FRegistration.swift @@ -63,9 +63,10 @@ class U2FRegistration { } } - // Use the highest per-registration counter value as our global counter value. + // Use the highest per-registration counter value plus one as our global + // counter value. if maxCtr > 0 { - Counter.current = maxCtr + Counter.current = maxCtr + 1 } } @@ -77,7 +78,8 @@ class U2FRegistration { let keyPair: KeyPair let applicationParameter: Data - // Key handle is application label plus 50 bytes of padding. Conformance tests require key handle to be >64 bytes. + // Key handle is application label plus 50 bytes of padding. Conformance + // tests require key handle to be >64 bytes. var keyHandle: Data { return padKeyHandle(keyPair.applicationLabel) } @@ -88,7 +90,8 @@ class U2FRegistration { // Generate a new registration. init?(applicationParameter ap: Data, inSEP sep: Bool) { - // TODO Specify applicationTag during creation. Alternatively, detect if setting tag fails. + // TODO Specify applicationTag during creation. Alternatively, detect if + // setting tag fails. guard let kp = KeyPair(label: U2FRegistration.namespace, inSEP: sep) else { return nil } kp.applicationTag = ap @@ -106,7 +109,8 @@ class U2FRegistration { guard let kp = KeyPair(label: U2FRegistration.namespace, appLabel: appLabel, signPrompt: prompt) else { return nil } keyPair = kp - // Read our application parameter from the keychain and make sure it matches. + // Read our application parameter from the keychain and make sure it + // matches. guard let appTag = keyPair.applicationTag else { return nil } applicationParameter = appTag From 9564745c57f90340df92ced64b0244a98842e9c4 Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Wed, 13 Jun 2018 08:54:11 -0600 Subject: [PATCH 4/5] unload kext by bundle-name in preinstall script --- install-scripts/preinstall | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/install-scripts/preinstall b/install-scripts/preinstall index 5e834df..5a6e980 100755 --- a/install-scripts/preinstall +++ b/install-scripts/preinstall @@ -1,12 +1,11 @@ #!/bin/bash -KEXT_DIR="/Library/Extensions" -KEXT="$KEXT_DIR/softu2f.kext" +KEXT_BUNDLE="com.github.SoftU2FDriver" LAUNCH_AGENT_PLIST="$HOME/Library/LaunchAgents/com.github.SoftU2F.plist" # This directory should already exist, but some users have had issues with it # being missing. mkdir -p $KEXT_DIR -kextunload $KEXT || true +kextunload -b $KEXT_BUNDLE || true sudo -u "${USER}" launchctl unload $LAUNCH_AGENT_PLIST || true From d1be69125dc42b5e494a010c62891a37fcac35fe Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Thu, 14 Jun 2018 09:37:39 -0600 Subject: [PATCH 5/5] Send proper error code when SEP and laptop is closed --- SoftU2FTool/KnownFacets.swift | 6 +++++- SoftU2FTool/U2FAuthenticator.swift | 10 +++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/SoftU2FTool/KnownFacets.swift b/SoftU2FTool/KnownFacets.swift index 13481f6..1fe4b78 100644 --- a/SoftU2FTool/KnownFacets.swift +++ b/SoftU2FTool/KnownFacets.swift @@ -15,5 +15,9 @@ let KnownFacets: [Data: String] = [ SHA256.digest("https://vault.bitwarden.com/app-id.json"): "https://vault.bitwarden.com", SHA256.digest("https://keepersecurity.com"): "https://keepersecurity.com", SHA256.digest("https://api-9dcf9b83.duosecurity.com"): "https://api-9dcf9b83.duosecurity.com", - SHA256.digest("https://dashboard.stripe.com"): "https://dashboard.stripe.com" + SHA256.digest("https://dashboard.stripe.com"): "https://dashboard.stripe.com", + + // When we return an error during authentication, Chrome will send a registration request with + // a bogus AppID. + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".data(using: .ascii)!: "bogus" ] diff --git a/SoftU2FTool/U2FAuthenticator.swift b/SoftU2FTool/U2FAuthenticator.swift index 6f92fd9..375d4ff 100644 --- a/SoftU2FTool/U2FAuthenticator.swift +++ b/SoftU2FTool/U2FAuthenticator.swift @@ -98,6 +98,14 @@ class U2FAuthenticator { let req = try APDU.RegisterRequest(raw: raw) let facet = KnownFacets[req.applicationParameter] + + // When we return an error during authentication, Chrome will send a registration request with + // a bogus AppID. + if facet == "bogus" { + self.sendError(status: .OtherError, cid: cid) + return + } + let notification = UserPresence.Notification.Register(facet: facet) UserPresence.test(notification) { tupSuccess in @@ -155,7 +163,7 @@ class U2FAuthenticator { if reg.inSEP && !laptopIsOpen { // Can't use SEP/TouchID if laptop is closed. - sendError(status: .OtherError, cid: cid) + sendError(status: .ConditionsNotSatisfied, cid: cid) return }