Skip to content
This repository was archived by the owner on Dec 15, 2020. It is now read-only.

Commit e795b8a

Browse files
authored
Merge pull request #49 from github/fix-counter
Global counter
2 parents 2757a8a + 56cba5b commit e795b8a

11 files changed

Lines changed: 238 additions & 98 deletions

File tree

SoftU2F.xcodeproj/project.pbxproj

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@
8585
F738F5871E4A3C09005680A2 /* DataReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5851E4A3C09005680A2 /* DataReaderTests.swift */; };
8686
F738F5881E4A3C09005680A2 /* DataWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5861E4A3C09005680A2 /* DataWriterTests.swift */; };
8787
F738F58A1E4A3C21005680A2 /* TestUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = F738F5891E4A3C21005680A2 /* TestUtil.swift */; };
88+
F761094D2056FE3F006BB8B0 /* Counter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761094C2056FE3F006BB8B0 /* Counter.swift */; };
89+
F761094F2057198A006BB8B0 /* CounterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761094E2057198A006BB8B0 /* CounterTests.swift */; };
90+
F761095120572117006BB8B0 /* Mutex.swift in Sources */ = {isa = PBXBuildFile; fileRef = F761095020572117006BB8B0 /* Mutex.swift */; };
8891
F7713A5F1F477BA90036A0D5 /* CLI.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7713A5D1F477BA90036A0D5 /* CLI.swift */; };
8992
F7713A601F477BA90036A0D5 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7713A5E1F477BA90036A0D5 /* Settings.swift */; };
9093
F7ABD9BE1E80603D00768FEC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F7ABD9BD1E80603D00768FEC /* Assets.xcassets */; };
@@ -243,6 +246,9 @@
243246
F738F5851E4A3C09005680A2 /* DataReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataReaderTests.swift; path = DataTests/DataReaderTests.swift; sourceTree = "<group>"; };
244247
F738F5861E4A3C09005680A2 /* DataWriterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataWriterTests.swift; path = DataTests/DataWriterTests.swift; sourceTree = "<group>"; };
245248
F738F5891E4A3C21005680A2 /* TestUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUtil.swift; sourceTree = "<group>"; };
249+
F761094C2056FE3F006BB8B0 /* Counter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Counter.swift; sourceTree = "<group>"; };
250+
F761094E2057198A006BB8B0 /* CounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CounterTests.swift; sourceTree = "<group>"; };
251+
F761095020572117006BB8B0 /* Mutex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = "<group>"; };
246252
F7713A5D1F477BA90036A0D5 /* CLI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLI.swift; sourceTree = "<group>"; };
247253
F7713A5E1F477BA90036A0D5 /* Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
248254
F7ABD9BD1E80603D00768FEC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -374,6 +380,8 @@
374380
5119862D1E3C1519006A3BBB /* KnownFacets.swift */,
375381
514F3D811E43C833008FA513 /* Keychain.swift */,
376382
514F3D861E43E828008FA513 /* KeyPair.swift */,
383+
F761094C2056FE3F006BB8B0 /* Counter.swift */,
384+
F761095020572117006BB8B0 /* Mutex.swift */,
377385
51FE30F01E410B3D00BAE824 /* Utils.swift */,
378386
51213EC51E3916EB005454E0 /* U2FHID.swift */,
379387
51B289E41E39903F00AD90CC /* U2FAuthenticator.swift */,
@@ -390,6 +398,7 @@
390398
51F090201E37E8C600F03AD3 /* SoftU2FTests */ = {
391399
isa = PBXGroup;
392400
children = (
401+
F761094E2057198A006BB8B0 /* CounterTests.swift */,
393402
51FE30EE1E40F3DB00BAE824 /* U2FRegistrationTests.swift */,
394403
51E2145D1E3823E0005B2864 /* SHA256Tests.swift */,
395404
51203C381E39234000F661DF /* U2FHIDTests.swift */,
@@ -852,7 +861,9 @@
852861
F7713A601F477BA90036A0D5 /* Settings.swift in Sources */,
853862
5119862E1E3C1519006A3BBB /* KnownFacets.swift in Sources */,
854863
51F090101E37E8C600F03AD3 /* AppDelegate.swift in Sources */,
864+
F761095120572117006BB8B0 /* Mutex.swift in Sources */,
855865
51213EC61E3916EB005454E0 /* U2FHID.swift in Sources */,
866+
F761094D2056FE3F006BB8B0 /* Counter.swift in Sources */,
856867
51E214601E3823E7005B2864 /* SHA256.swift in Sources */,
857868
51B289E51E39903F00AD90CC /* U2FAuthenticator.swift in Sources */,
858869
514F3D821E43C833008FA513 /* Keychain.swift in Sources */,
@@ -867,6 +878,7 @@
867878
isa = PBXSourcesBuildPhase;
868879
buildActionMask = 2147483647;
869880
files = (
881+
F761094F2057198A006BB8B0 /* CounterTests.swift in Sources */,
870882
51E214641E382529005B2864 /* WebSafeBase64Tests.swift in Sources */,
871883
5131C1B01E3B9C62006A820C /* IntegrationTests.swift in Sources */,
872884
51E2145E1E3823E0005B2864 /* SHA256Tests.swift in Sources */,
@@ -1159,7 +1171,7 @@
11591171
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/inc";
11601172
INFOPLIST_FILE = SoftU2FToolTests/Info.plist;
11611173
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
1162-
LIBRARY_SEARCH_PATHS = "/usr/local/Cellar/libu2f-host/1.1.3/lib";
1174+
LIBRARY_SEARCH_PATHS = "/usr/local/Cellar/libu2f-host/1.1.5/lib";
11631175
PRODUCT_BUNDLE_IDENTIFIER = com.github.SoftU2FToolTests;
11641176
PRODUCT_NAME = "$(TARGET_NAME)";
11651177
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1182,7 +1194,7 @@
11821194
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/inc";
11831195
INFOPLIST_FILE = SoftU2FToolTests/Info.plist;
11841196
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
1185-
LIBRARY_SEARCH_PATHS = "/usr/local/Cellar/libu2f-host/1.1.3/lib";
1197+
LIBRARY_SEARCH_PATHS = "/usr/local/Cellar/libu2f-host/1.1.5/lib";
11861198
PRODUCT_BUNDLE_IDENTIFIER = com.github.SoftU2FToolTests;
11871199
PRODUCT_NAME = "$(TARGET_NAME)";
11881200
PROVISIONING_PROFILE_SPECIFIER = "";

SoftU2FTool/CLI.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ class CLI {
5353
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.")
5454
print(" - Application parameter: This is the sha256 of the app-id of the site.")
5555
print(" - Known facet: For some sites we know the application parameter → site name mapping.")
56-
print(" - Counter: How many times this registration has been used.")
5756
print(" — In SEP: Whether this registration's private key is stored in the SEP.")
5857
print("")
5958

@@ -67,7 +66,6 @@ class CLI {
6766
print("Known facet: N/A")
6867
}
6968

70-
print("Counter: ", reg.counter)
7169
print("In SEP: ", reg.inSEP)
7270
print("")
7371
}

SoftU2FTool/Counter.swift

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//
2+
// Counter.swift
3+
// SoftU2F
4+
//
5+
// Created by Benjamin P Toews on 3/12/18.
6+
//
7+
8+
import Foundation
9+
10+
class Counter {
11+
12+
private static let service = "Soft U2F"
13+
private static let serviceLen = UInt32(service.utf8.count)
14+
private static let account = "counter"
15+
private static let accountLen = UInt32(account.utf8.count)
16+
private static let mtx = Mutex()
17+
18+
static var next: UInt32 {
19+
mtx.lock()
20+
defer { mtx.unlock() }
21+
22+
let c = current ?? 0
23+
current = c + 1
24+
return c
25+
}
26+
27+
// assumes mtx is already locked
28+
static var current: UInt32? {
29+
get {
30+
var valLen: UInt32 = 0
31+
var val: UnsafeMutableRawPointer? = nil
32+
33+
let err = SecKeychainFindGenericPassword(nil, serviceLen, service, accountLen, account, &valLen, &val, nil)
34+
if err != errSecSuccess {
35+
if err != errSecItemNotFound {
36+
print("Error from keychain: \(err)")
37+
}
38+
return nil
39+
}
40+
if val == nil { return nil }
41+
defer { SecKeychainItemFreeContent(nil, val) }
42+
43+
guard let strVal = NSString(bytes: val!, length: Int(valLen), encoding: String.Encoding.utf8.rawValue) as String? else {
44+
return nil
45+
}
46+
47+
return UInt32(strVal)
48+
}
49+
50+
set {
51+
let err: OSStatus
52+
if let val: UInt32 = newValue {
53+
let strVal = String(val)
54+
let strValLen = UInt32(strVal.utf8.count)
55+
if let it = item {
56+
err = SecKeychainItemModifyContent(it, nil, strValLen, strVal)
57+
} else {
58+
err = SecKeychainAddGenericPassword(nil, serviceLen, service, accountLen, account, strValLen, strVal, nil)
59+
}
60+
} else {
61+
if let it = item {
62+
err = SecKeychainItemDelete(it)
63+
} else {
64+
return
65+
}
66+
}
67+
68+
if err != errSecSuccess {
69+
print("Error from keychain: \(err)")
70+
}
71+
}
72+
}
73+
74+
// assumes mtx is already locked
75+
private static var item: SecKeychainItem? {
76+
var it: SecKeychainItem? = nil
77+
78+
let err = SecKeychainFindGenericPassword(nil, serviceLen, service, accountLen, account, nil, nil, &it)
79+
if err != errSecSuccess {
80+
if err != errSecItemNotFound {
81+
print("Error from keychain: \(err)")
82+
}
83+
return nil
84+
}
85+
86+
return it
87+
}
88+
}

SoftU2FTool/KnownFacets.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,9 @@ let KnownFacets: [Data: String] = [
1616
SHA256.digest("https://keepersecurity.com"): "https://keepersecurity.com",
1717
SHA256.digest("https://api-9dcf9b83.duosecurity.com"): "https://api-9dcf9b83.duosecurity.com",
1818
SHA256.digest("https://dashboard.stripe.com"): "https://dashboard.stripe.com",
19-
SHA256.digest("https://id.fedoraproject.org/u2f-origins.json"): "https://id.fedoraproject.org"
19+
SHA256.digest("https://id.fedoraproject.org/u2f-origins.json"): "https://id.fedoraproject.org",
20+
21+
// When we return an error during authentication, Chrome will send a registration request with
22+
// a bogus AppID.
23+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".data(using: .ascii)!: "bogus"
2024
]

SoftU2FTool/Mutex.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// Mutex.swift
3+
// SoftU2F
4+
//
5+
// Created by Benjamin P Toews on 3/12/18.
6+
// Copyright © 2018 GitHub. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
class Mutex {
12+
private var semaphore = DispatchSemaphore(value: 1)
13+
14+
func lock() {
15+
semaphore.wait()
16+
}
17+
18+
func unlock() {
19+
semaphore.signal()
20+
}
21+
}

SoftU2FTool/U2FAuthenticator.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ class U2FAuthenticator {
9898
let req = try APDU.RegisterRequest(raw: raw)
9999

100100
let facet = KnownFacets[req.applicationParameter]
101+
102+
// When we return an error during authentication, Chrome will send a registration request with
103+
// a bogus AppID.
104+
if facet == "bogus" {
105+
self.sendError(status: .OtherError, cid: cid)
106+
return
107+
}
108+
101109
let notification = UserPresence.Notification.Register(facet: facet)
102110

103111
UserPresence.test(notification) { tupSuccess in
@@ -155,7 +163,7 @@ class U2FAuthenticator {
155163

156164
if reg.inSEP && !laptopIsOpen {
157165
// Can't use SEP/TouchID if laptop is closed.
158-
sendError(status: .OtherError, cid: cid)
166+
sendError(status: .ConditionsNotSatisfied, cid: cid)
159167
return
160168
}
161169

@@ -169,8 +177,8 @@ class U2FAuthenticator {
169177
return
170178
}
171179

172-
let counter = reg.counter
173-
var ctrBigEndian = counter.bigEndian
180+
let ctr = Counter.next
181+
var ctrBigEndian = ctr.bigEndian
174182

175183
let payloadSize = req.applicationParameter.count + 1 + MemoryLayout<UInt32>.size + req.challengeParameter.count
176184
var sigPayload = Data(capacity: payloadSize)
@@ -185,7 +193,7 @@ class U2FAuthenticator {
185193
return
186194
}
187195

188-
let resp = AuthenticationResponse(userPresence: 0x01, counter: counter, signature: sig)
196+
let resp = AuthenticationResponse(userPresence: 0x01, counter: ctr, signature: sig)
189197
self.sendMsg(msg: resp, cid: cid)
190198
return
191199
}

0 commit comments

Comments
 (0)