Compare commits

...

6 Commits
1.1.0 ... 1.1.1

9 changed files with 57 additions and 23 deletions

17
CHANGELOG.md Normal file
View File

@ -0,0 +1,17 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.1.0] - 2019-02-17
### Added
- Code cleanup
- Buffer over-read bug fix
- U2F counter endianness bug fix
- More testing
- Extension interface to U2F and FIDO2
- Read firmware version
- Read RNG bytes

View File

@ -80,7 +80,7 @@ docker-build:
docker build -t $(DOCKER_IMAGE) .
docker run --rm -v "$(CURDIR)/builds:/builds" \
-v "$(CURDIR)/in-docker-build.sh:/in-docker-build.sh" \
$(DOCKER_IMAGE) /in-docker-build.sh $(SOLO_VERSIONISH)
$(DOCKER_IMAGE) "./in-docker-build.sh" $(SOLO_VERSIONISH)
CPPCHECK_FLAGS=--quiet --error-exitcode=2

1
STABLE_VERSION Normal file
View File

@ -0,0 +1 @@
1.1.1

View File

@ -1,13 +1,16 @@
# tl;dr
Create [`/etc/udev/rules.d/99-solo.rules`](https://github.com/solokeys/solo/blob/master/99-solo.rules) and add the following (which assumes your user is in group `plugdev`):
Create a file like [`/etc/udev/rules.d/99-solo.rules`](https://github.com/solokeys/solo/blob/master/99-solo.rules), for instance the following rules should cover access in all cases:
```
# Solo
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev", SYMLINK+="solokey"
# Solo bootloader + firmware
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev"
# ST DFU bootloader
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", TAG+="uaccess", GROUP="plugdev"
# U2F Zero
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", SYMLINK+="u2fzero"
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev"
```
Then run

View File

@ -118,7 +118,7 @@ int16_t extend_u2f(struct u2f_request_apdu* req, uint32_t len)
{
if ( ! is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests
{
rcode = U2F_SW_WRONG_PAYLOAD;
rcode = U2F_SW_WRONG_DATA;
printf1(TAG_EXT, "Ignoring U2F auth request\n");
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
goto end;

View File

@ -196,6 +196,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
if (control == U2F_AUTHENTICATE_CHECK)
{
printf1(TAG_U2F, "CHECK-ONLY\r\n");
if (u2f_appid_eq(&req->kh, req->app) == 0)
{
return U2F_SW_CONDITIONS_NOT_SATISFIED;
@ -213,7 +214,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
)
{
return U2F_SW_WRONG_PAYLOAD;
return U2F_SW_WRONG_DATA;
}

View File

@ -42,12 +42,11 @@
// Command status responses
#define U2F_SW_NO_ERROR 0x9000
#define U2F_SW_WRONG_DATA 0x6984
#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985
#define U2F_SW_INS_NOT_SUPPORTED 0x6d00
#define U2F_SW_WRONG_LENGTH 0x6700
#define U2F_SW_CLASS_NOT_SUPPORTED 0x6E00
#define U2F_SW_WRONG_PAYLOAD 0x6a80
#define U2F_SW_WRONG_DATA 0x6a80
#define U2F_SW_INSUFFICIENT_MEMORY 0x9210
// Delay in milliseconds to wait for user input

View File

@ -5,7 +5,7 @@ version=${1:-master}
export PREFIX=/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/
cd /solo/targets/stm32l432
git fetch
git fetch --tags
git checkout ${version}
version=$(git describe)

View File

@ -12,6 +12,10 @@
# Script for testing correctness of CTAP2/CTAP1 security token
from __future__ import print_function, absolute_import, unicode_literals
import sys, os, time
from random import randint
from binascii import hexlify
import array, struct, socket
from fido2.hid import CtapHidDevice, CTAPHID
from fido2.client import Fido2Client, ClientError
@ -20,10 +24,10 @@ from fido2.ctap1 import CTAP1
from fido2.ctap2 import *
from fido2.cose import *
from fido2.utils import Timeout, sha256
import sys, os, time
from random import randint
from binascii import hexlify
import array, struct, socket
from fido2.attestation import Attestation
from solo.fido2 import forceUDPBackend
# Set up a FIDO 2 client using the origin https://example.com
@ -35,6 +39,11 @@ def ForceU2F(client, device):
client._do_get_assertion = client._ctap1_get_assertion
def VerifyAttestation(attest, data):
verifier = Attestation.for_type(attest.fmt)
verifier().verify(attest.att_statement, attest.auth_data, data.hash)
class Packet(object):
def __init__(self, data):
l = len(data)
@ -415,7 +424,7 @@ class Tester:
rp, user, challenge, pin=PIN, exclude_list=[]
)
t2 = time.time() * 1000
attest.verify(data.hash)
VerifyAttestation(attest, data)
print("Register valid (%d ms)" % (t2 - t1))
cred = attest.auth_data.credential_data
@ -465,7 +474,7 @@ class Tester:
)
print(attest.auth_data.counter)
t2 = time.time() * 1000
attest.verify(data.hash)
VerifyAttestation(attest, data)
print("Register valid (%d ms)" % (t2 - t1))
sys.stdout.flush()
@ -511,7 +520,7 @@ class Tester:
attest, data = self.client.make_credential(
rp, user, challenge, pin=PIN, exclude_list=[]
)
attest.verify(data.hash)
VerifyAttestation(attest, data)
# verify endian-ness is correct
assert attest.auth_data.counter < 0x10000
cred = attest.auth_data.credential_data
@ -535,7 +544,7 @@ class Tester:
attest, data = self.client.make_credential(
rp, user, challenge, pin=PIN, exclude_list=exclude_list
)
attest.verify(data.hash)
VerifyAttestation(attest, data)
cred = attest.auth_data.credential_data
creds.append(cred)
print("PASS")
@ -665,7 +674,7 @@ class Tester:
rp, user0, challenge, pin=PIN, exclude_list=[], rk=True
)
t2 = time.time() * 1000
attest.verify(data.hash)
VerifyAttestation(attest, data)
creds.append(attest.auth_data.credential_data)
print("Register valid (%d ms)" % (t2 - t1))
@ -687,7 +696,7 @@ class Tester:
rp, users[i], challenge, pin=PIN, exclude_list=[], rk=True
)
t2 = time.time() * 1000
attest.verify(data.hash)
VerifyAttestation(attest, data)
print("Register valid (%d ms)" % (t2 - t1))
creds.append(attest.auth_data.credential_data)
@ -710,7 +719,7 @@ class Tester:
rp, users[1], challenge, pin=PIN, exclude_list=[], rk=True
)
t2 = time.time() * 1000
attest.verify(data.hash)
VerifyAttestation(attest, data)
creds = creds[:2] + creds[3:] + [attest.auth_data.credential_data]
print("Register valid (%d ms)" % (t2 - t1))
@ -775,7 +784,7 @@ class Tester:
rp, user, challenge, pin=PIN, exclude_list=[], rk=True
)
t2 = time.time() * 1000
attest.verify(data.hash)
VerifyAttestation(attest, data)
creds = [attest.auth_data.credential_data]
print("Register valid (%d ms)" % (t2 - t1))
@ -825,6 +834,10 @@ def test_find_brute_force():
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "sim":
print("Using UDP backend.")
forceUDPBackend()
t = Tester()
t.find_device()
# t.test_hid()