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

Commit

Permalink
Merge pull request #49 from github/fix-counter
Browse files Browse the repository at this point in the history
Global counter
  • Loading branch information
mastahyeti authored Jun 14, 2018
2 parents 2757a8a + 56cba5b commit e795b8a
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 98 deletions.
16 changes: 14 additions & 2 deletions SoftU2F.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -243,6 +246,9 @@
F738F5851E4A3C09005680A2 /* DataReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataReaderTests.swift; path = DataTests/DataReaderTests.swift; sourceTree = "<group>"; };
F738F5861E4A3C09005680A2 /* DataWriterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataWriterTests.swift; path = DataTests/DataWriterTests.swift; sourceTree = "<group>"; };
F738F5891E4A3C21005680A2 /* TestUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUtil.swift; sourceTree = "<group>"; };
F761094C2056FE3F006BB8B0 /* Counter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Counter.swift; sourceTree = "<group>"; };
F761094E2057198A006BB8B0 /* CounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CounterTests.swift; sourceTree = "<group>"; };
F761095020572117006BB8B0 /* Mutex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mutex.swift; sourceTree = "<group>"; };
F7713A5D1F477BA90036A0D5 /* CLI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLI.swift; sourceTree = "<group>"; };
F7713A5E1F477BA90036A0D5 /* Settings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
F7ABD9BD1E80603D00768FEC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
Expand Down Expand Up @@ -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 */,
Expand All @@ -390,6 +398,7 @@
51F090201E37E8C600F03AD3 /* SoftU2FTests */ = {
isa = PBXGroup;
children = (
F761094E2057198A006BB8B0 /* CounterTests.swift */,
51FE30EE1E40F3DB00BAE824 /* U2FRegistrationTests.swift */,
51E2145D1E3823E0005B2864 /* SHA256Tests.swift */,
51203C381E39234000F661DF /* U2FHIDTests.swift */,
Expand Down Expand Up @@ -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 */,
Expand All @@ -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 */,
Expand Down Expand Up @@ -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 = "";
Expand All @@ -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 = "";
Expand Down
2 changes: 0 additions & 2 deletions SoftU2FTool/CLI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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("")

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

print("Counter: ", reg.counter)
print("In SEP: ", reg.inSEP)
print("")
}
Expand Down
88 changes: 88 additions & 0 deletions SoftU2FTool/Counter.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
6 changes: 5 additions & 1 deletion SoftU2FTool/KnownFacets.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ let KnownFacets: [Data: String] = [
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://id.fedoraproject.org/u2f-origins.json"): "https://id.fedoraproject.org"
SHA256.digest("https://id.fedoraproject.org/u2f-origins.json"): "https://id.fedoraproject.org",

// When we return an error during authentication, Chrome will send a registration request with
// a bogus AppID.
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".data(using: .ascii)!: "bogus"
]
21 changes: 21 additions & 0 deletions SoftU2FTool/Mutex.swift
Original file line number Diff line number Diff line change
@@ -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()
}
}
16 changes: 12 additions & 4 deletions SoftU2FTool/U2FAuthenticator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand All @@ -169,8 +177,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<UInt32>.size + req.challengeParameter.count
var sigPayload = Data(capacity: payloadSize)
Expand All @@ -185,7 +193,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
}
Expand Down
Loading

0 comments on commit e795b8a

Please sign in to comment.