Giter VIP home page Giter VIP logo

python-fido2's Introduction

python-fido2

Github actions build

Provides library functionality for communicating with a FIDO device over USB as well as verifying attestation and assertion signatures.

This library aims to support the FIDO U2F and FIDO 2 protocols for communicating with a USB authenticator via the Client-to-Authenticator Protocol (CTAP 1 and 2). In addition to this low-level device access, classes defined in the fido2.client and fido2.server modules implement higher level operations which are useful when interfacing with an Authenticator, or when implementing WebAuthn support for a Relying Party.

For usage, see the examples/ directory.

References

These links related to WebAuthn and FIDO2 can help you get started:

License

This project, with the exception of the files mentioned below, is licensed under the BSD 2-clause license. See the COPYING file for the full license text.

This project contains source code from pyu2f (https://github.com/google/pyu2f) which is licensed under the Apache License, version 2.0. These files are located in fido2/hid/. See http://www.apache.org/licenses/LICENSE-2.0, or the COPYING.APLv2 file for the full license text.

This project also bundles the public suffix list (https://publicsuffix.org) which is licensed under the Mozilla Public License, version 2.0. This file is stored as fido2/public_suffix_list.dat. See https://mozilla.org/MPL/2.0/, or the COPYING.MPLv2 file for the full license text.

Requirements

fido2 is compatible with Python 3.7 and later, and is tested on Windows, MacOS, and Linux. Support for OpenBSD, FreeBSD, and NetBSD is provided as-is and relies on community contributions.

Installation

fido2 is installable by running the following command:

pip install fido2

To install the dependencies required for communication with NFC authenticators, instead use:

pip install fido2[pcsc]

Under Windows 10 (1903 or later) access to FIDO devices is restricted and requires running as Administrator. This library can still be used when running as non-administrator, via the fido.client.WindowsClient class. An example of this is included in the file examples/credential.py.

Under Linux you will need to add a Udev rule to be able to access the FIDO device, or run as root. For example, the Udev rule may contain the following:

#Udev rule for allowing HID access to Yubico devices for FIDO support.

KERNEL=="hidraw*", SUBSYSTEM=="hidraw", \
  MODE="0664", GROUP="plugdev", ATTRS{idVendor}=="1050"

There may be a package already available for your distribution that does this for you, see: https://support.yubico.com/hc/en-us/articles/360013708900-Using-Your-U2F-YubiKey-with-Linux

Under FreeBSD you will either need to run as root or add rules for your device to /etc/devd.conf, which can be automated by installing security/u2f-devd:

# pkg install u2f-devd

Dependencies

This project depends on Cryptography. For instructions on installing this dependency, see https://cryptography.io/en/latest/installation/.

NFC support is optionally available via PC/SC, using the pyscard library. For instructions on installing this dependency, see https://github.com/LudovicRousseau/pyscard/blob/master/INSTALL.md.

Development

For development of the library we use poetry. To set up the dev environment, run this command in the root directory of the repository:

poetry install

We also use pre-commit to run some scans on the code prior to committing.

Running tests

While many tests can run on their own, some require a connected U2F or FIDO2 device to run.

poetry run pytest

python-fido2's People

Contributors

a-detiste avatar bigfootjon avatar ckataki avatar claui avatar cmilam87 avatar conorpp avatar coobas avatar dagheyman avatar dainnilsson avatar daringer avatar davepeck avatar dotlambda avatar dsanders11 avatar emlun avatar enrikb avatar fabianhenneke avatar gmarano avatar grembo avatar jonfen avatar joostd avatar kaczmarczyck avatar klali avatar kongeo avatar merlokk avatar oleksandr-kuzmenko avatar polhenarejos avatar prillan avatar syntaxcase avatar worr avatar ziima avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-fido2's Issues

Fix cbor encoding cycle

Cycle through cbor encoding doesn't return the original value. I'd expect

from fido2 import cbor
a = 42
a == cbor.loads(cbor.dumps(a))

to be true, but it isn't, because loads returns a tuple of two. I'd suggest to modify loads to return only decoded value and provide other function for cases where needed (ctap2 module).

signed source tarball

For version 0.3.0 we have signed source tarball on release page. Can we have that for version 0.4.0 as well? Thanks!

Resident Key / UserHandle Authentication?

Follow-up from issue #75:

I was able to get resident keys to work with 0.8.1, thanks! In order to get it to work, I had to delete 'allowCredentials' from public_key (it was an empty list) before calling client.get_assertion.

I have the following code in place but it doesn't seem ideal:

if not public_key['allowCredentials']:
    del public_key['allowCredentials']

Otherwise it works!

Thanks,
Patrick

USER_VERIFICATION PREFERRED not working in server.py

Hello,

I am trying to run server.py:
server = Fido2Server(rp, user_verification=USER_VERIFICATION.PREFERED) works fine.
server = Fido2Server(rp, user_verification=USER_VERIFICATION.REQUIRED) no prompt from browser or os..

Is the field decoded in cbor.js or its not implemented ?

Thank you

Clarify relationship to webauthn

WebAuthn is in the news these days. It seems there is a relationship between WebAuthn and FIDO2 and this code, and clarifying that in the README etc would be helpful.

Fido2Client should expose CTAP2 info

I believe the API exposed by Fido2Client can be improved. Let's say I have a security key which supports CTAP2 and have a PIN configured. Right now there is no easy way to check if there is PIN set before calling make_credential or get_assertion. Calling a method and catching ValueError as shown in examples/credential.py leads to bad user experience. When I run credential.py it first asks to touch the device and then asks for PIN which is incorrect and confusing.

I see there is a ctap2 member in Fido2Client but it's not always set because the client can fallback to CTAP1. So I have to either to check for this or explicitly create a CTAP2 object.

Maybe consider to always expose ctap2 member which is None in case of CTAP1. Or directly provide methods for manipulating CTAP2 info?

Regarding Yubico Email

Regarding Yubico email that was sent yesterday to developers 'Developers implementing FIDO U2F, update to Chrome coming in v 72', Is the library affected by this and needs a fix, or it is safe with Chrome v72+?

Thanks

Touch ID is working

Hi,

This isn't a bug, this is info that Touch ID on Macbook using Chrome 70 is working fine and it is recognized as 'packed'

Question about server interaction with authenticator

Hi 👋

In other examples i have seen previously (without python-fido2), the server returns the view containing the webauthn javascript that communicates with the authenticator on the device. (the server does a redirect to a page that it hosts)

Having had a look through the server example here, am i right in thinking that the ctap code is run locally (not hosted from the server)? If the CTAP code is hosted locally, how does the server talk to the client to say that the assertions need to take place

I'm working on a project where I'd like to use fido2 to provide usernameless/passwordless auth, but i don't want to use a webbrowser; all the ctap code would live locally on the device

Many thanks

Installation on Ubuntu tries to install uhid-freebsd

I encountered this issue while trying to install gimme-aws-creds on Xubuntu 16.04. It pulls in fido2 which triggered the attempted installation of uhid-freebsd.

Installing the prior version of fido2 avoids the issue and unblocked me. However, it is unclear why this FreeBSD package was getting pulled into a LInux installation.

Issue with Py2.7 Django

I trying to integrating this repo with Django 1.8 on Python 2.7 and I getting this strange in object loaded in JS

view.py
registration_data, state = server.register_begin({
'id': request.user.username,
'name': request.user.first_name + " " + request.user.last_name,
'displayName': request.user.username,
'icon': settings.STATIC_URL + "img/favicon.ico"
}, [])

return HttpResponse(cbor.dumps(registration_data),content_type='application/octet-stream')

JS Object received from begin_registeration
selection_351

The problem that user dict keys are represented in binary so the navigator.credentials.create() fails as no username is provided.

Confusion about CTAPHID response cmd field for CBOR messages

The following code from fido2/hid.py assumes that successful CTAPHID responses will have the same command field as the initial request.

    def call(self, cmd, data=b'', event=None, on_keepalive=None):
        event = event or Event()
        self._dev.InternalSend(TYPE_INIT | cmd, bytearray(data))
        last_ka = None
        while not event.is_set():
            status, resp = self._dev.InternalRecv()
            status ^= TYPE_INIT
            if status == cmd:
                return bytes(resp)
            elif status == CTAPHID.ERROR:
                raise CtapError(resp[0])
            elif status == CTAPHID.KEEPALIVE:
                ka_status = resp[0]
                if on_keepalive and last_ka != ka_status:
                    try:
                        ka_status = STATUS(ka_status)
                    except ValueError:
                        pass  # Unknown status value
                    last_ka = ka_status
                    on_keepalive(ka_status)
                continue
            else:
                raise CtapError(CtapError.ERR.INVALID_COMMAND)

        self.call(CTAPHID.CANCEL, b'', _SingleEvent())
        raise CtapError(CtapError.ERR.KEEPALIVE_CANCEL)

In the CTAP spec, for HID CBOR requests, it says the response should use CTAPHID_MSG in the command field (rather than CTAPHID_CBOR). Is this a mistake in the spec?

alpine install broke on 0.7.2

perhaps this isnt a concern at all, but on alpine latest and some pinned versions, as of 0.7.2, this four-line docker file is no longer happy:

docker build -f Dockerfile-FidoNotBestFriendRightNow .
Sending build context to Docker daemon  15.36kB
Step 1/4 : FROM alpine:latest
latest: Pulling from library/alpine
89d9c30c1d48: Already exists
Digest: sha256:c19173c5ada610a5989151111163d28a67368362762534d8a8121ce95cf2bd5a
Status: Downloaded newer image for alpine:latest
 ---> 965ea09ff2eb
Step 2/4 : RUN apk --update add py-pip
 ---> Running in 9333bbd464a3
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
(1/12) Installing libbz2 (1.0.6-r7)
(2/12) Installing expat (2.2.8-r0)
(3/12) Installing libffi (3.2.1-r6)
(4/12) Installing gdbm (1.13-r1)
(5/12) Installing ncurses-terminfo-base (6.1_p20190518-r0)
(6/12) Installing ncurses-terminfo (6.1_p20190518-r0)
(7/12) Installing ncurses-libs (6.1_p20190518-r0)
(8/12) Installing readline (8.0.0-r0)
(9/12) Installing sqlite-libs (3.28.0-r1)
(10/12) Installing python2 (2.7.16-r1)
(11/12) Installing py-setuptools (40.8.0-r1)
(12/12) Installing py2-pip (18.1-r0)
Executing busybox-1.30.1-r2.trigger
OK: 65 MiB in 26 packages
Removing intermediate container 9333bbd464a3
 ---> e9a5a9b7c953
Step 3/4 : RUN pip install --upgrade pip
 ---> Running in aad56e921bdf
Collecting pip
  Downloading https://files.pythonhosted.org/packages/00/b6/9cfa56b4081ad13874b0c6f96af8ce16cfbc1cb06bedf8e9164ce5551ec1/pip-19.3.1-py2.py3-none-any.whl (1.4MB)
Installing collected packages: pip
  Found existing installation: pip 18.1
    Uninstalling pip-18.1:
      Successfully uninstalled pip-18.1
Successfully installed pip-19.3.1
Removing intermediate container aad56e921bdf
 ---> deaa4a1558ca
Step 4/4 : RUN pip install 'fido2<=0.7.2'
 ---> Running in c462207ee2c8
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support
Collecting fido2<=0.7.2
  Downloading https://files.pythonhosted.org/packages/97/2b/dd7ecc8838881ec1f68b1d581821933d54d7ed8f3ef16874ebf2ed277e2b/fido2-0.7.2.tar.gz (188kB)
    ERROR: Command errored out with exit status 1:
     command: /usr/bin/python2 -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-EYkTQ9/fido2/setup.py'"'"'; __file__='"'"'/tmp/pip-install-EYkTQ9/fido2/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-install-EYkTQ9/fido2/pip-egg-info
         cwd: /tmp/pip-install-EYkTQ9/fido2/
    Complete output (9 lines):
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-EYkTQ9/fido2/setup.py", line 33, in <module>
        if StrictVersion(__version__) < StrictVersion("20.2"):
      File "/usr/lib/python2.7/distutils/version.py", line 40, in __init__
        self.parse(vstring)
      File "/usr/lib/python2.7/distutils/version.py", line 107, in parse
        raise ValueError, "invalid version number '%s'" % vstring
    ValueError: invalid version number '40.8.0.post20190503'
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
The command '/bin/sh -c pip install 'fido2<=0.7.2'' returned a non-zero code: 1
~/local/dockerfiles

attestation_object.verify doesn't exist

When i execute the credential.py example i always get the following error AttributeError: 'AttestationObject' object has no attribute 'verify'
Making me believe AttestationObject doesn't have a verify method please either make a verify method or fix the example.

Kind regards.
Lars

Get Authencator ID

Which attribute holds an authenticator unique identifier to make sure that the authenticator is NOT used by another user?

In U2F, we used to check the X509 certificate.

Thanks in advance

'uhid-freebsd' package build failed

I am trying to install yubikey-manager on macos (10.14.6), but building wheel for uhid-freebsd is failing. Somehow it is not skipped for this platform.

> pip install yubikey-manager

Collecting yubikey-manager
Requirement already satisfied: click in ./env/lib/python3.5/site-packages (from yubikey-manager) (6.7)
Collecting fido2>=0.7 (from yubikey-manager)
Requirement already satisfied: cryptography in ./env/lib/python3.5/site-packages (from yubikey-manager) (2.7)
Requirement already satisfied: pyscard in ./env/lib/python3.5/site-packages (from yubikey-manager) (1.9.9)
Requirement already satisfied: six in ./env/lib/python3.5/site-packages (from yubikey-manager) (1.12.0)
Requirement already satisfied: pyusb in ./env/lib/python3.5/site-packages (from yubikey-manager) (1.0.2)
Requirement already satisfied: pyopenssl in ./env/lib/python3.5/site-packages (from yubikey-manager) (19.0.0)
Collecting uhid-freebsd>=1.2.1 (from fido2>=0.7->yubikey-manager)
  Using cached https://files.pythonhosted.org/packages/55/c8/aee05809c37437b5aeca56608e9b12c368a97cdd1be017642e3a8f1ecd88/uhid-freebsd-1.2.1.tar.gz
Requirement already satisfied: asn1crypto>=0.21.0 in ./env/lib/python3.5/site-packages (from cryptography->yubikey-manager) (0.24.0)
Requirement already satisfied: cffi!=1.11.3,>=1.8 in ./env/lib/python3.5/site-packages (from cryptography->yubikey-manager) (1.12.3)
Requirement already satisfied: pycparser in ./env/lib/python3.5/site-packages (from cffi!=1.11.3,>=1.8->cryptography->yubikey-manager) (2.19)
Building wheels for collected packages: uhid-freebsd
  Building wheel for uhid-freebsd (setup.py) ... error
  ERROR: Command errored out with exit status 1:
   command: /Users/daniel/code/oll/taf/env/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/lc/c_lvyn5x6cbd12ysjly61qcr0000gn/T/pip-install-vfbfeayn/uhid-freebsd/setup.py'"'"'; __file__='"'"'/private/var/folders/lc/c_lvyn5x6cbd12ysjly61qcr0000gn/T/pip-install-vfbfeayn/uhid-freebsd/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /private/var/folders/lc/c_lvyn5x6cbd12ysjly61qcr0000gn/T/pip-wheel-k5az3543 --python-tag cp35
       cwd: /private/var/folders/lc/c_lvyn5x6cbd12ysjly61qcr0000gn/T/pip-install-vfbfeayn/uhid-freebsd/
  Complete output (12 lines):
  running bdist_wheel
  running build
  running build_ext
  building 'uhid_freebsd' extension
  creating build
  creating build/temp.macosx-10.14-x86_64-3.5
  clang -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/Users/daniel/.pyenv/versions/3.5.6/include/python3.5m -c uhid_freebsd.cpp -o build/temp.macosx-10.14-x86_64-3.5/uhid_freebsd.o
  uhid_freebsd.cpp:15:10: fatal error: 'dev/usb/usb_ioctl.h' file not found
  #include <dev/usb/usb_ioctl.h>
           ^~~~~~~~~~~~~~~~~~~~~
  1 error generated.
  error: command 'clang' failed with exit status 1
  ----------------------------------------
  ERROR: Failed building wheel for uhid-freebsd
  Running setup.py clean for uhid-freebsd
Failed to build uhid-freebsd
Installing collected packages: uhid-freebsd, fido2, yubikey-manager
  Running setup.py install for uhid-freebsd ... error
    ERROR: Command errored out with exit status 1:
     command: /Users/daniel/code/oll/taf/env/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/lc/c_lvyn5x6cbd12ysjly61qcr0000gn/T/pip-install-vfbfeayn/uhid-freebsd/setup.py'"'"'; __file__='"'"'/private/var/folders/lc/c_lvyn5x6cbd12ysjly61qcr0000gn/T/pip-install-vfbfeayn/uhid-freebsd/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /private/var/folders/lc/c_lvyn5x6cbd12ysjly61qcr0000gn/T/pip-record-ocgvl2a5/install-record.txt --single-version-externally-managed --compile --install-headers /Users/daniel/code/oll/taf/env/include/site/python3.5/uhid-freebsd
         cwd: /private/var/folders/lc/c_lvyn5x6cbd12ysjly61qcr0000gn/T/pip-install-vfbfeayn/uhid-freebsd/
    Complete output (12 lines):
    running install
    running build
    running build_ext
    building 'uhid_freebsd' extension
    creating build
    creating build/temp.macosx-10.14-x86_64-3.5
    clang -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/Users/daniel/.pyenv/versions/3.5.6/include/python3.5m -c uhid_freebsd.cpp -o build/temp.macosx-10.14-x86_64-3.5/uhid_freebsd.o
    uhid_freebsd.cpp:15:10: fatal error: 'dev/usb/usb_ioctl.h' file not found
    #include <dev/usb/usb_ioctl.h>
             ^~~~~~~~~~~~~~~~~~~~~
    1 error generated.
    error: command 'clang' failed with exit status 1
    ----------------------------------------
ERROR: Command errored out with exit status 1: /Users/daniel/code/oll/taf/env/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/lc/c_lvyn5x6cbd12ysjly61qcr0000gn/T/pip-install-vfbfeayn/uhid-freebsd/setup.py'"'"'; __file__='"'"'/private/var/folders/lc/c_lvyn5x6cbd12ysjly61qcr0000gn/T/pip-install-vfbfeayn/uhid-freebsd/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /private/var/folders/lc/c_lvyn5x6cbd12ysjly61qcr0000gn/T/pip-record-ocgvl2a5/install-record.txt --single-version-externally-managed --compile --install-headers /Users/daniel/code/oll/taf/env/include/site/python3.5/uhid-freebsd Check the logs for full command output

TypeError: Struct() argument 1 must be string, not unicode

Version 0.5.0
Environment: RHEL 7, Python 2.7.5

Traceback:

  att_obj = AttestationObject(data['attestationObject'])
File 'venv/lib/python2.7/site-packages/fido2/ctap2.py', line 372 in __init__
  self.auth_data = AuthenticatorData(data[AttestationObject.KEY.AUTH_DATA] 
File 'venv/lib/python2.7/site-packages/fido2/ctap2.py', line 240 in __init__
  self.counter = struct.unpack('>I', self[33:33+4])[0]
TypeError: Struct() argument 1 must be string, not unicode

The problem stems from limitations of the built-in struct module in the Python 2.7.5 version.

Recommend warning users about earlier versions of Python 2.7. I can report that Python 2.7.6 on Ubuntu Trusty does not exhibit this problem.

NFC Fido2

Do you have interest to make this library compatible with NFC u2f/fido2 channel via pyscard ?

[BUG] when running on windows < 1903, import `fido2.client` results in an error

As mentioned, this is running on Windows 1809. Upon importing fido2.client, the below error is raised.

  File "c:\users\containeradministrator\.virtualenvs\data-nggunt9q\lib\site-packages\fido2\client.py", line 44, in <module>
    from .win_api import (
  File "c:\users\containeradministrator\.virtualenvs\data-nggunt9q\lib\site-packages\fido2\win_api.py", line 531, in <module>
    WEBAUTHN_API_VERSION = WEBAUTHN.WebAuthNGetApiVersionNumber()
  File "c:\python38\Lib\ctypes\__init__.py", line 386, in __getattr__
    func = self.__getitem__(name)
  File "c:\python38\Lib\ctypes\__init__.py", line 391, in __getitem__
    func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'WebAuthNGetApiVersionNumber' not found

I propose either handing the error in the library so that other aspects can be used on older versions of windows or raise a more meaningful error to be handled app side.

Resident Key / UserHandle Authentication?

I'm trying to get resident keys to work with the example server. I can get resident keys to work with webauthn.me but not with the example server using a YubiKey 5 NFC. I am modifying the register_begin call to pass resident_key=True

@app.route("/api/register/begin", methods=["POST"])
def register_begin():
    registration_data, state = server.register_begin(
        {
            "id": b"user_id",
            "name": "a_user",
            "displayName": "A. User",
            "icon": "https://example.com/image.png",
        },
        credentials,
        resident_key=True,
        user_verification="discouraged",
    )

and it does look like Chrome sees the resident key request by saying:

"A record of your visit to this site will be kept on your security key."

but I do not see a userHandle in the authentication response:

@app.route("/api/authenticate/complete", methods=["POST"])
def authenticate_complete():
    if not credentials:
        abort(404)

    data = cbor.decode(request.get_data())
    print("authenticate finish data:", data)

authenticate finish data: {u'credentialId': "\x17\xfbZ{\xa5\xbcB\x12\xa5\xe3\xd3'\xd7\x97\xb0\xac", u'clientDataJSON': '{"challenge":"sbtMTP_IGixS4-Ur6uNhxqpty3jfsIKN8nDzWOu_Eeg","origin":"https://localhost:10000","type":"webauthn.get"}', u'authenticatorData': 'I\x96\r\xe5\x88\x0e\x8cht4\x17\x0fdv`[\x8f\xe4\xae\xb9\xa2\x862\xc7\x99\\xf3\xba\x83\x1d\x97c\x05\x00\x00\x00\t', u'signature': '0E\x02 \x16)\xc8\x1d\x82\xac\x14\xcd\xe0\x8c\xb3\xe2s\xb2\xc1GN\x17u\t\x81R"\x96\xc7?\xbb\x8b\x10\xfa\x9c\xdd\x02!\x00\xc2\xdb\xea\x84yP\xe9\x9c\x87\x9a5\xc9G\x9fR\xd5\\x97\x97\xf7\xd1\xe5\xaa\x80\xb0>4/3\xef0\xf4'}

Am I doing something wrong?

UPDATE: I found it, had to add "userHandle" to authenticate.html:

      body: CBOR.encode({
        "credentialId": new Uint8Array(assertion.rawId),
        "authenticatorData": new Uint8Array(assertion.response.authenticatorData),
        "clientDataJSON": new Uint8Array(assertion.response.clientDataJSON),
        "userHandle": new Uint8Array(assertion.response.userHandle),
        "signature": new Uint8Array(assertion.response.signature)
      })

Google Titan USB Keys not being recognized

Hi all,

Not sure if this is a known/solved issue, but my Google Titan USB keys are not being recognized when using the list_devices() options when trying to check ctap or hid. Am I missing something simple here, or is this simply not supported?

When I was trying to debug and go through each device, none of the page information matched 0xF1D0.

Edit: Additional info:

Both USB A and USB c keys are not being recognized on Windows 10 using both front-panel IO and back-panel IO. They are, however, recognized inside of device manager as fido compliant devices.

Thanks in advance

Implement Attestation for TPM

Currently, there is only fido-u2f, android-safetynet and packet attestation implemented.
With the release of Windows 1903, Windows Hello can be used as a WebAuthn device, which is supported with Chrome, Edge and I think also Firefox.
Implementing the attestation for tpm modules, fido2 could be brought to more users.

Incorrect CTAPHID_CANCEL response processing

According to https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#usb-hid-cancel:

The CTAPHID_CANCEL command MAY be sent by the client during ongoing processing of a CTAPHID_CBOR request. The CTAP2_ERR_KEEPALIVE_CANCEL response MUST be the response to that request, not an error response in the HID transport.

Thus if the client sends a CTAPHID_CANCEL command to cancel an outstanding CTAPHID_CBOR request, then the authenticator must respond with "9000012d". However, when this happens, CtapHidDevice::Call() incorrectly interprets this response as an invalid command, raising CtapError(CtapError.ERR.INVALID_COMMAND) instead of CtapError(CtapError.ERR.KEEPALIVE_CANCEL).

raise CtapError(CtapError.ERR.INVALID_COMMAND)

Missing "alg" parameter in key agreement public key

According to https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html the COSE_Key-encoded public key MUST contain the optional "alg" parameter. However, the key agreement public key returned by PinProtocolV1::get_shared_secret() is missing the "alg" parameter, see

python-fido2/fido2/ctap2.py

Lines 802 to 807 in 1021538

key_agreement = {
1: 2,
-1: 1,
-2: int2bytes(pn.x, 32),
-3: int2bytes(pn.y, 32)
}

Add methods to obtain EllipticCurvePublicNumbers from a key

Currently, CoseKey (and its subclasses) abstract the entire chain from parsing the public key data to using the public key to verify the signature of an arbitrary message. I can see why this is desirable, as it entirely abstracts RSA versus elliptic curve approaches.

However, it would be nice if the ES256 subclass also supported getting the actual EllipticCurvePublicNumbers object. This would allow me to use methods from the Python Cryptography library to implement an SSH agent that exports FIDO keys (well, more cleanly than my current proof-of-concept work, anyway). Some background: an SSH agent needs to report available ECDSA keys using the SEC 1 v2.0 section 2.3.3 format, which is available via the EllipticCurvePublicNumbers.encode_point() method.

It would also be nice to be able to obtain the RSAPublicNumbers objects as well (for similar reasons).

server example is broken against 0.4.0

Recent changes in example endpoint register_begin require two values returning from server.register_begin
but just one is coming in 0.4.0, leading to:
File "/server/server.py", line 73, in register_begin
}, credentials)
ValueError: not enough values to unpack (expected 2, got 1)

The Security Key doesn't look familiar, please try a different one.

I am trying to build a thick client application for windows which will do Fido2 2FA against an [IdP](https://en.wikipedia.org/wiki/Identity_provider#:~:text=An%20identity%20provider%20(abbreviated%20IdP,user%20authentication%20as%20a%20service.)

Now when I do an primary authentication call using username and password I get a challenge and credential id in a JSON response and then I am trying to pass them to Yubikey 5 NFC to get signed assertion but I am getting below error.

FidoError

Here is the code snippet.

def create_client():
    client = WindowsClient("https://IdPUrl.com")
    return client


def assertion(initiated_response):
    #Parsing the received JSON response for Cred_ID and Challenge
    credential_id = initiated_response['credentialId']
    challenge = initiated_response['challenge']
    allow_list = [{"type": "public-key", "id":
        bytes(credential_id, 'utf-8')
                   }]
    clientdev = create_client()
    # Authenticate the credential
    result = clientdev.get_assertion(
        {
            "rpId": "IdPUrl.com",
            "challenge": bytes(challenge, 'utf-8'),
            "allowCredentials": allow_list
        },
        pin=pin,
    ).get_response(
        0
    )

Can you help me me point out where I am going wrong!!

Use tox

To easily check if the library works under different version of python, tox would be of a great help.

AttributeError: 'list' object has no attribute 'read'

When I try to run the command pipenv run server in the server directory, I get this error message:

Traceback (most recent call last):
  File "/usr/bin/pipenv", line 11, in <module>
    load_entry_point('pipenv==11.9.0', 'console_scripts', 'pipenv')()
  File "/usr/lib/python3/dist-packages/pipenv/vendor/click/core.py", line 722, in _call_
    return self.main(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/pipenv/vendor/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python3/dist-packages/pipenv/vendor/click/core.py", line 1066, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python3/dist-packages/pipenv/vendor/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python3/dist-packages/pipenv/vendor/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/pipenv/cli.py", line 602, in run
    core.do_run(command=command, args=args, three=three, python=python)
  File "/usr/lib/python3/dist-packages/pipenv/core.py", line 2200, in do_run
    command = ' '.join(project.scripts[command])
  File "/usr/lib/python3/dist-packages/pipenv/project.py", line 374, in scripts
    scripts[k] = shlex.split(v, posix=True)
  File "/usr/lib/python3.7/shlex.py", line 305, in split
    return list(lex)
  File "/usr/lib/python3.7/shlex.py", line 295, in _next_
    token = self.get_token()
  File "/usr/lib/python3.7/shlex.py", line 105, in get_token
    raw = self.read_token()
  File "/usr/lib/python3.7/shlex.py", line 136, in read_token
    nextchar = self.instream.read(1)
AttributeError: 'list' object has no attribute 'read'

Test failure in test_EdDSA_parse_verify

I'm building this package in our build system. Versions up until 0.5.0 were working fine, but with the latest 0.6.0 release, one test case is failing:

======================================================================
[   67s] FAIL: test_EdDSA_parse_verify (test.test_cose.TestCoseKey)
[   67s] ----------------------------------------------------------------------
[   67s] Traceback (most recent call last):
[   67s]   File "/home/abuild/rpmbuild/BUILD/fido2-0.6.0/test/test_cose.py", line 84, in test_EdDSA_parse_verify
[   67s]     self.assertIsInstance(key, EdDSA)
[   67s] AssertionError: {1: 1, 3: -8, -1: 6, -2: '\xee\x9b!\x804\x05\xd3\xcfE`\x1eX\xb6\xf4\xc0n\xa98b\xde\x87\xd3\xaf\x90<Xp\xa5\x01n\x86\xf5'} is not an instance of <class 'fido2.cose.EdDSA'>

Not sure what is at fault here (library version, etc.). The full build log can be found here.

On another distribution (openSUSE Factory / Tumbleweed) this works just fine, but libraries versions are newer, etc.: https://build.opensuse.org/package/live_build_log/openSUSE:Factory/python-fido2/standard/x86_64

Please let me know what additional information you need.

Consistently getting ValueError('Wrong challenge in response.')

I apologize as this is likely an issue in my code, and not the repo- but I have tried this for days to no avail, and the lack of documentation is exacerbating my confusion.

I am running a local https server and testing FIDO2 keys. I generate a key like this:

registration_data, state = server.register_begin({
            u'id': '1',
            u'name': 'my user',
            u'displayName': 'my user',
             }, credentials)
request.session['fido2_state'] = state
# generate pubkey to pass to front end credential 
publicKey = {
       'challenge': websafe_encode(registration_data['publicKey']['challenge']),
       'rp': {
           'name':'Example Inc.',
           'id': 'localhost',
        },
        'user': {
             'id': 1,
             'name': '[email protected]',
              'displayName': 'Alice von Wunderland'
         },
        'pubKeyCredParams': [
                { 'type': 'public-key', 'alg': -7  },
                { 'type': 'public-key', 'alg': -257 }
         ]
}
return render(request, self.template_name, {'registration_data':  publicKey})

And in the front end:

//Get response from server and convert values to array buffer 
publicKey = {{ registration_data | safe }}
challenge = publicKey['challenge']
user_id = publicKey['user']['id']
publicKey['challenge'] = str2ab(challenge)
publicKey['user']['id'] = str2ab(user_id)
navigator.credentials.create({ 'publicKey': publicKey }) .then(function(attestation) {
                return fetch('/fido/', {
                    method: 'POST',
                    credentials: 'same-origin',
                    headers: {'Content-Type': 'application/cbor'},
                    body: CBOR.encode({
                      "attestationObject": new Uint8Array(attestation.response.attestationObject),
                      "clientDataJSON": new Uint8Array(attestation.response.clientDataJSON),
                    });
             });
        });

Once it's posted to server, I get the data from the request and try to verify

       # verify response from server
        data = cbor.loads(request.body)[0]
        client_data = ClientData(data['clientDataJSON'])
        att_obj = AttestationObject(data['attestationObject'])
        state = request.session['fido2_state']
        auth_data = server.register_complete(
            state,
            client_data,
            att_obj
        )

This consistently returns

  File "/usr/local/lib/python2.7/dist-packages/fido2/server.py", line 180, in register_complete
    raise ValueError('Wrong challenge in response.')

I am completely lost. I have tried the few examples I have found online. However I truly have no idea how to proceed. My guess is my encoding of the challenge in the original registration challenge generation is incorrect, but I'm not sure what to do. I have tried encoding this in a variety of ways, completely unsuccessfully.

I would appreciate any hints here. If this is too far out of the scope for these issues, I apologize and will close it out.

Not working session in examples.

examples/server/server.py is not working.
The following error occurred in register phase.

127.0.0.1 - - [14/Jul/2018 18:18:24] "POST /api/register/complete HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/Users/prprhyt/.pyenv/versions/3.5.2/lib/python3.5/site-packages/flask/app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/prprhyt/.pyenv/versions/3.5.2/lib/python3.5/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/Users/prprhyt/.pyenv/versions/3.5.2/lib/python3.5/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/prprhyt/.pyenv/versions/3.5.2/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/Users/prprhyt/.pyenv/versions/3.5.2/lib/python3.5/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/prprhyt/.pyenv/versions/3.5.2/lib/python3.5/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/prprhyt/.pyenv/versions/3.5.2/lib/python3.5/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/prprhyt/.pyenv/versions/3.5.2/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/Users/prprhyt/.pyenv/versions/3.5.2/lib/python3.5/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/prprhyt/.pyenv/versions/3.5.2/lib/python3.5/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/prprhyt/gitdir/python-fido2/examples/server/server.py", line 94, in register_complete
    session['challenge'], client_data, att_obj)
  File "/Users/prprhyt/.pyenv/versions/3.5.2/lib/python3.5/site-packages/werkzeug/local.py", line 377, in <lambda>
    __getitem__ = lambda x, i: x._get_current_object()[i]
KeyError: 'challenge'

Add annotations

Annotations would help a lot. Any chance they we can see them soon?

Can we maybe not die from non-canonical CBOR?

currently playing around a bit and tried few of the example scripts on a GoTrust Idem Card

https://www.gotrustid.com/idem-card

and well upon running get_info.py the script immediately dies due to the CBOR not being canonical

my1@my1-qb:~$ python3 python-fido2/examples/get_info.py 
CONNECT: CtapPcscDevice(REINER SCT cyberJack RFID basis 00 00)
CTAPHID protocol version: 2
Traceback (most recent call last):
  File "python-fido2/examples/get_info.py", line 58, in <module>
    info = ctap2.get_info()
  File "/home/my1/.local/lib/python3.6/site-packages/fido2/ctap2.py", line 755, in get_info
    return self.send_cbor(CTAP2.CMD.GET_INFO, parse=Info)
  File "/home/my1/.local/lib/python3.6/site-packages/fido2/ctap2.py", line 656, in send_cbor
    "Got: {}\n".format(enc_h) + "Expected: {}".format(exp_h)
ValueError: Non-canonical CBOR from Authenticator.
Got: b'a60182684649444f5f325f30665532465f563202816b686d61632d73656372657403509f0d8150baa54c009299ad62c8bb4e8704a464706c6174f462726bf569636c69656e7450696ef5627570f505190400068101'
Expected: b'a60182684649444f5f325f30665532465f563202816b686d61632d73656372657403509f0d8150baa54c009299ad62c8bb4e8704a462726bf5627570f564706c6174f469636c69656e7450696ef505190400068101'

considering there are actual authenticators flying around that dont nesecarily run canonical and unsurprisigly cannot be updated (a bad trend Yubico as far as I can see started as one of the first well known FIDO devices), it would kinda break stuff if canonical is enforced.

for now all of the other CTAP2 capable devices I am currently possessing which are

  • Yubikey 5 (Fido 2.0)
  • Blue Yubi with NFC (Fido 2.1)
  • eWBM Goldengate G310 (FIDO2.1)
  • Solokeys Solo (on both Fido 2.0 and 2.1 firmwares)
  • Hypersecu HyperFido Pro mini (Fido 2.0)

do NOT seem to have this problem U2F devices as far as the script says dont even do CBOR so they are out all the way

my1@my1-qb:~$ python3 python-fido2/examples/get_info.py 
CONNECT: CtapHidDevice(/dev/hidraw0)
CTAPHID protocol version: 2
Device does not support CBOR
WINK sent!

FIDO functionality becomes unusable with "Invalid value size specified" error

I'm running into an issue where my Yubikey 5 NFC becomes unusable after a some time (typically fine after a reboot, but then this issue comes back after a couple of days). Doesn't seem specific to older or newer library versions (had this same issue in the 0.7.x versions on a ubuntu 19.04 system, and I'm seeing it still with a fresh ykman install on a ubuntu 19.10 system)

The exact output looks like:

troyready@notebook:~$ .local/bin/ykman fido list
Traceback (most recent call last):
  File ".local/bin/ykman", line 8, in <module>
    sys.exit(main())
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/ykman/cli/__main__.py", line 273, in main
    cli(obj={})
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/click/decorators.py", line 17, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/ykman/cli/fido.py", line 112, in list_creds
    controller = ctx.obj['controller']
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/ykman/cli/util.py", line 127, in __getitem__
    self.resolve()
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/ykman/cli/util.py", line 124, in resolve
    self._objects[k] = f()
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/ykman/cli/__main__.py", line 194, in resolve_device
    dev = _run_cmd_for_single(ctx, subcmd.name, transports, reader)
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/ykman/cli/__main__.py", line 132, in _run_cmd_for_single
    return descriptor.open_device(transports)
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/ykman/descriptor.py", line 96, in open_device
    for drv in _list_drivers(transports):
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/ykman/descriptor.py", line 164, in _list_drivers
    for dev in open_fido():
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/ykman/driver_fido.py", line 97, in open_devices
    for dev in CtapHidDevice.list_devices(descriptor_filter):
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/fido2/hid.py", line 135, in list_devices
    for d in hidtransport.hid.Enumerate():
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/fido2/_pyu2f/linux.py", line 193, in Enumerate
    ParseReportDescriptor(rd_file.read(), desc)
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/fido2/_pyu2f/linux.py", line 149, in ParseReportDescriptor
    usage_page = ReadLsbBytes(rd, pos + 1, value_length)
  File "/home/troyready/.local/venvs/yubikey-manager/lib/python3.7/site-packages/fido2/_pyu2f/linux.py", line 86, in ReadLsbBytes
    raise OSError('Invalid value size specified')
OSError: Invalid value size specified

If I add a debug print line to that ReadLsbBytes function, it's a bunch of 1s, a few 2s, and then a 0 causes that ^ exception.

Not sure if there's some method of resetting or troubleshooting I can provide, but would love to help.

Publish Release for 0.9.0-dev0

The last release v0.8.1 for fido2 was on November 25 2019. There have been a number of awesome fixes since then. For example, v0.8.1 has a segfault when enumerating HID devices on MacOS Big Sur which is all ready fixed by the new HID cleanup in a862fda.

Would it be possible to publish an interim release to PyPI so that the fixes can be picked up downstream. At the moment, the only way to consume it is as an egg from this repo, i.e:

pip install git+https://github.com/Yubico/python-fido2@507818c95ed84f543511455bc7fef646801f1cd8#egg=fido2

pip install broken in 2.7 env

If you comment out this from setup.py:

extras_require={
    ':python_version < "3.4"': ['enum34']
},

it works again. Error is:

Downloading https://files.pythonhosted.org/packages/58/0d/655ef526ab14b8eecc70f773294f15b23402d5184da290c4f23d5d893048/fido2-0.4.0.tar.gz (141kB)
100% |████████████████████████████████| 143kB 6.6MB/s
Complete output from command python setup.py egg_info:
/usr/lib/python2.7/distutils/dist.py:267: UserWarning: Unknown distribution option: 'python_requires'
warnings.warn(msg)
error in fido2 setup command: Invalid environment marker: python_version < "3.4"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.