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

Global counter #49

Merged
merged 6 commits into from
Jun 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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