Coder Social home page Coder Social logo

python-u2flib-server's Introduction

u2flib-server

Provides functionality for working with the server side aspects of the U2F protocol as defined in the FIDO specifications. It supports Python 2.7, Python 3.3+ and PyPy 2.7+.

Note
This project is deprecated and new features will not be added. Please see python-fido2 which replaces this project.

To read more about U2F and how to use a U2F library, visit developers.yubico.com/U2F.

Dependencies

u2flib-server depends on cryptography, which requires libffi, OpenSSL, and a C compiler to build. On a Debian or Ubuntu system, the build dependencies can be installed with the following command:

$ sudo apt-get install build-essential libssl-dev libffi-dev python-dev

For Windows the cryptography project provides prebuilt wheels. For other platforms refer to cryptography installation.

Installation

u2flib-server is installable by running the following command:

$ pip install python-u2flib-server

Check out the code

Run these commands to check out the source code:

git clone https://github.com/Yubico/python-u2flib-server.git
cd python-u2flib-server
git submodule init
git submodule update

Build a source release

To build a source release tar ball, run this command:

python setup.py sdist

The resulting build will be created in the dist/ subdirectory.

Example

See examples/u2f_server.py for a working example of a HTTP server for U2F enrollment and authentication. u2f_server.py can be run as a stand-alone server, and can be used to test a U2F client implementation, such as python-u2flib-host, using for example cURL.

The examples below show cURL command to register a U2F device, and to authenticate it.

Registration

Registration is initiated by sending a request to the server:

$ curl http://localhost:8081/enroll
{"appId": "http://localhost:8081", "registeredKeys": [], "registerRequests": [{"version": "U2F_V2", "challenge": "9TCtiRRLBFqMokOWfepjej99lMKQhZfm20Sgtay-FMs"}]}

The RegisterRequest data is then fed to the U2F client, resulting in the RegisterResponse data, which is passed back to the server:

$ curl http://localhost:8081/bind -d'data={"registrationData": "BQQNSrGo5bCdPyQNh1etGjidrJPBwTqittKe5DgKWyumIuGSnQxIHzM8Xd9W2eBrAJezRf7nIbxVRYkiA2G_teiEQLJa3tSyM-irgZHNXwsHC-YnfpXJ_uQkRMsgx37oAefHJI3RsBe4yCN2noa-jO1mgtgRrPK405QdcpI7xVk3XmAwggGHMIIBLqADAgECAgkAmb7osQyi7BwwCQYHKoZIzj0EATAhMR8wHQYDVQQDDBZZdWJpY28gVTJGIFNvZnQgRGV2aWNlMB4XDTEzMDcxNzE0MjEwM1oXDTE2MDcxNjE0MjEwM1owITEfMB0GA1UEAwwWWXViaWNvIFUyRiBTb2Z0IERldmljZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDvhl91zfpg9n7DeCedcQ8gGXUnemiXoi-JEAxz-EIhkVsMPAyzhtJZ4V3CqMZ-MOUgICt2aMxacMX9cIa8dgS2jUDBOMB0GA1UdDgQWBBQNqL-TV04iaO6mS5tjGE6ShfexnjAfBgNVHSMEGDAWgBQNqL-TV04iaO6mS5tjGE6ShfexnjAMBgNVHRMEBTADAQH_MAkGByqGSM49BAEDSAAwRQIgXJWZdbvOWdhVaG7IJtn44o21Kmi8EHsDk4cAfnZ0r38CIQD6ZPi3Pl4lXxbY7BXFyrpkiOvCpdyNdLLYbSTbvIBQOTBEAiBs0qu8RRZDf4qJo5qnHOd6hNDu9aEyNGQCeHp47D6-9gIgST3rq1JrUn_xvPh5AAGsn64cLvJlF_V0MF2A73tkLOc", "clientData": "eyJvcmlnaW4iOiAiaHR0cDovL2xvY2FsaG9zdDo4MDgxIiwgImNoYWxsZW5nZSI6ICI5VEN0aVJSTEJGcU1va09XZmVwamVqOTlsTUtRaFpmbTIwU2d0YXktRk1zIiwgInR5cCI6ICJuYXZpZ2F0b3IuaWQuZmluaXNoRW5yb2xsbWVudCJ9","version":"U2F_V2"}'
true

The result, "true", indicates that registration was successful.

Authentication

Authentication for a previously registered U2F device is done by sending a request to the server:

$ curl http://localhost:8081/sign
{"appId": "http://localhost:8081", "registeredKeys": [{"version": "U2F_V2", "appId": "http://localhost:8081", "keyHandle": "slre1LIz6KuBkc1fCwcL5id-lcn-5CREyyDHfugB58ckjdGwF7jII3aehr6M7WaC2BGs8rjTlB1ykjvFWTdeYA"}], "challenge": "FnueX-NpT9kB7I41dc8DvPXU1-yj7oO_cBT3e9PWOAw"}

The AuthenticateRequest data is then fed to the U2F client, resulting in an AuthenticateResponse object which is passed back to the server:

$ curl http://localhost:8081/verify -d'data={"keyHandle": "slre1LIz6KuBkc1fCwcL5id-lcn-5CREyyDHfugB58ckjdGwF7jII3aehr6M7WaC2BGs8rjTlB1ykjvFWTdeYA", "signatureData": "AQAAAAEwRgIhALhe7LTwnBHTPQQIGbn_wPR80S7-HPPliZh966vL3VeiAiEA35w-BVDROwdLGlztLgejw9bnXSrYY0-3EC-_qhi0XaI", "clientData": "eyJvcmlnaW4iOiAiaHR0cDovL2xvY2FsaG9zdDo4MDgxIiwgImNoYWxsZW5nZSI6ICJGbnVlWC1OcFQ5a0I3STQxZGM4RHZQWFUxLXlqN29PX2NCVDNlOVBXT0F3IiwgInR5cCI6ICJuYXZpZ2F0b3IuaWQuZ2V0QXNzZXJ0aW9uIn0"}'
{"touch": 1, "counter": 1}

The response indicates success, giving the U2F devices internal counter value, as well as the value of the user presence parameter.

python-u2flib-server's People

Contributors

archoversight avatar dainnilsson avatar jnschaeffer avatar klali avatar lowks avatar mark-adams avatar medina avatar minisu avatar moreati 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-u2flib-server's Issues

Python 3 wheels may depend on enum34

Using recent versions of setuptools, wheels will automatically be built locally and cached to improve installation speed.

However, if the wheel happens to be built with Python 2.7, it will have the enum34 dependency added to the wheel meta data.

Trying to install python-u2flib-server in another python 3.6 virtualenv will then install the python 2.7-built wheel, which will also pull in enum34.

The way to fix this issue is described here:
https://hynek.me/articles/conditional-python-dependencies/

Logging

We should improve logging so all requests and responses are logged and outcome of all important operations are logged (e.g., signature verifications).

InvalidSignature verifying register / auth requests on Mac OS X

Documenting for future folks who have this same problem.

The default OS X install of OpenSSL is 0.9.8, which has some issues with the ECDSA functions (see issue #14 ).

This manifests as Exception: InvalidSignature when calling complete_register, which is a huge pain in the neck to debug.

You can test if this is likely the reason for InvalidSignature errors with:

import cryptography.hazmat.backends

multi_backend=cryptography.hazmat.backends.default_backend()
ossl_be=multi_backend._backends[1]
print ossl_be.openssl_version_text()

If that prints 0.9.8, you're going to have this problem.

When installing python-u2flib-server, use

env LDFLAGS="-L$(brew --prefix openssl)/lib" CFLAGS="-I$(brew --prefix openssl)/include" python setup.py install

Or:

brew install libffi
brew install hidapi
brew install openssl
pip install cython

env LDFLAGS="-L$(brew --prefix openssl)/lib" CFLAGS="-I$(brew --prefix openssl)/include" pip install python-u2flib-server

Maintainers, I haven't verified the whole series of install steps on OS X with a clean install, though I recall that cython (for chid.pxd errors) and hidapi were helpful in my testing. Before I burn a few hours writing a PR against the docs for OS X / spend time on test case writing during setup.py to figure out if the openssl version is solid, is there demand for such a thing?

Run tests on PyPy

The tests (currently) pass on PyPy, but require PyPy >= 2.6. As TravisCI uses an older version of PyPy we cannot currently automate these tests. Once TravisCI supports a compatible version of PyPy we should enable PyPy in .travis.yml

This issue depends on: travis-ci/travis-ci#4756

TypeError: Object of type 'bytes' is not JSON serializable (encoding raw_response.user_presence)

uf2_v2.py's verify_authenticate returns raw_response.user_presence, which will then be passed to json.dumps as the touch value. This fails on py3 as the input type is bytes. I'm unsure why it appears to work in the instructions (additionally, the instructions show it as a raw unicode character, which seems undesirable). This value should just be converted to an integer before passing to json.dumps.

Release a new version

Any way we can get a new version released to PyPI with the cryptography support?

I'd even take a pre-release version :-)

Demo site: "FIDO Client error: 1 (OTHER ERROR)"

I have just purchased 2 Yubikey NEOs. I was able to register them with Google but am now having trouble. When I try and use the demo site https://demo.yubico.com/u2f?tab=register I get the following:

 Traceback (most recent call last):
  File "/root/python-u2flib-server-demo/examples/yubiauth_server.py", line 161, in __call__
    raise Exception("FIDO Client error: %s" % error)
Exception: FIDO Client error: 1 (OTHER ERROR)

Same for both keys. Have restarted Chrome and rebooted.

Chrome Version 56.0.2924.87 (64-bit)
MacOS 10.12.3

Openssl / M2Crypt -> Exception: Attestation signature verification failed!

I'm attempting to use this library in a Django app. I'm successfully able to generate a challenge and get a response from the U2F device. However, when I attempt to call u2f.complete_register(request,response) I'm getting an Attestation signature verification failed! error.

Python 2.7
Django 1.7
M2Crypto 0.22.3
Openssl 1.0.2d_1
OS X 10.10.3

Request data:

{"challenge": "SohCJaPJvuPZpobbeU7KWSQl8V6qkD_MLkLzbP0ZbJI","version":"U2F_V2","appId":"https://dev.myapp.com:8000"}

Response data:

{"registrationData":"BQRLFW_LoxzZF6ruTXs43dTiG4R10crtWTznY2Nf2KWZzr8QHVRNJArQ2a-LsKxHldwpaMtifK8-NPBSIWKyOH2pQG70Vg0yr5WPQPvUA_T7tMwKp5-mbANWjohFJBBJVeoom6VODrwooE87NVvH0VPbANnapY2bWTfDviyidCWUvKswggItMIIBF6ADAgECAgQFtgV5MAsGCSqGSIb3DQEBCzAuMSwwKgYDVQQDEyNZdWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAwMDBaGA8yMDUwMDkwNDAwMDAwMFowKDEmMCQGA1UEAwwdWXViaWNvIFUyRiBFRSBTZXJpYWwgOTU4MTUwMzMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT9uN6zoe1w62NsBm62AGmWpflw_LXbiPw7MF1B5ZZvDBtUuFL-8KCQftF_O__CnU0yG5z4qEos6qA4yr011ZjeoyYwJDAiBgkrBgEEAYLECgIEFTEuMy42LjEuNC4xLjQxNDgyLjEuMTALBgkqhkiG9w0BAQsDggEBAH7T-2zMJSAT-C8hjCo32mAx0g5_MIHa_K6xKPx_myM5FL-2TWE18XziIfp2T0U-8Sc6jOlllWRCuy8eR0g_c33LyYtYU3f-9QsnDgKJ-IQ28a3PSbJiHuXjAt9VW5q3QnLgafkYFJs97E8SIosQwPiN42r1inS7RCuFrgBTZL2mcCBY_B8th5tTARHqYOhsY_F_pZRMyD8KommEiz7jiKbAnmsFlT_LuPR-g6J-AHKmPDKtZIZOkm1xEvoZl_eDllb7syvo94idDwFFUZonr92ORrBMpCkNhUC2NLiGFh51iMhimdzdZDXRZ4o6bwp0gpxN0_cMNSTR3fFteK3SG2QwRgIhAJi7YVdZbsMDY-r03vPUSOj3hOXp4kx1m3xBoC9HVbXXAiEAsh1SpVIMlLxFfBXIKKX3YDI9fSWudP5UcglZyU-A4JE","challenge":"SohCJaPJvuPZpobbeU7KWSQl8V6qkD_MLkLzbP0ZbJI","version":"U2F_V2","appId":"https://dev.medcrypt.com:8000","clientData":"eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZmluaXNoRW5yb2xsbWVudCIsImNoYWxsZW5nZSI6IlNvaENKYVBKdnVQWnBvYmJlVTdLV1NRbDhWNnFrRF9NTGtMemJQMFpiSkkiLCJvcmlnaW4iOiJodHRwczovL2Rldi5tZWRjcnlwdC5jb206ODAwMCIsImNpZF9wdWJrZXkiOiIifQ"}

Any suggestions?

Hard-coded Yubico products in u2f_v2.py

I'm planning to use u2f_v2.py, but i'm concerned about hard-coded Yubico products:

FIXSIG = [
    'CN=Yubico U2F EE Serial 776137165',
    'CN=Yubico U2F EE Serial 1086591525',
    'CN=Yubico U2F EE Serial 1973679733',
    'CN=Yubico U2F EE Serial 13503277888',
    'CN=Yubico U2F EE Serial 13831167861',
    'CN=Yubico U2F EE Serial 14803321578'
]

What does it mean ? Where those serial come from and what is wrong with their X509 certificates ?

Broken tests?

What is the right way to run the tests?

nosetest (using py2) leads to:
from .soft_u2f_v2 import SoftU2FDevice
ValueError: Attempted relative import in non-package

python setup.py test fails with:

...
File "/usr/lib/python2.7/unittest/loader.py", line 91, in loadTestsFromName
module = import('.'.join(parts_copy))`
File "/usr/lib/python2.7/test/regrtest.py", line 184, in
for module in sys.modules.itervalues():
RuntimeError: dictionary changed size during iteration

Remove dependency on pyasn1

python-u2flib-server uses pyasn1 for a single purpose - to implement get_ext_by_oid().
The recent release of cryptography 1.2 fixes pyca/cryptography#2288 this can be achieved with Certificate.extensions.get_extension_for_oid().

However, get_ext_by_oid() and ExtensionMatcher are implemented around comparing the raw bytes of the extension and cryptography only exposes these when the oid is of an UnrecognizedExtension. In general the cryptography ethos strongly discourages exposing raw bytes.

Should we take this opportunity to change the return type of get_ext_by_oid()?

Support for Python 3

This is currently blocked by the dependency on M2Crypto. Reading the discussion in martinpaljak/M2Crypto#23 is not very encouraging. M2Crypto seems rather poorly maintained in general.

Poking around the source a bit, my impression is that M2Crypto could be replaced with pyopenssl. Can someone more familiar with the project confirm or deny?

pop instead of get challenge

In the example server, wouldn't it be better to do this:

challenge = user.pop('_u2f_challenge_')

instead of the current

challenge = user['_u2f_challenge_']

This way, noone can replay the authentication.

publicKey required in sign request

In version 5.0, when performing complete_authentication, the publicKey is extracted only from request, which makes usage difficult. The request is send to the client (browser), but it doesn't need the publicKey and thus it shouldn't be send to it.

I suggest to return devices argument to the complete_authentication function to provide a mapping between the handle and public key.

Error with command `swig` during `sudo pip install python-u2flib-server`

------------------------------------------------------------
/usr/bin/pip run on Wed Oct 21 22:02:07 2015
Requirement already satisfied (use --upgrade to upgrade): python-u2flib-server in /usr/local/lib/python2.7/dist-packages
Downloading/unpacking M2Crypto (from python-u2flib-server)
  Getting page https://pypi.python.org/simple/M2Crypto/
  URLs to search for versions for M2Crypto (from python-u2flib-server):
  * https://pypi.python.org/simple/M2Crypto/
  Analyzing links from page https://pypi.python.org/simple/m2crypto/
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.17.tar.gz#md5=27272497ce13a3e78af028f7d0fd2d6f (from https://pypi.python.org/simple/m2crypto/), version: 0.17
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.19.1.tar.gz#md5=c92286fdf0a75f017e72122c2832d5ff (from https://pypi.python.org/simple/m2crypto/), version: 0.19.1
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.19.tar.gz#md5=f9fa8f38121be614d4d70e1884fcf260 (from https://pypi.python.org/simple/m2crypto/), version: 0.19
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.20.1.tar.gz#md5=6a7420664310f424be4e63dfbe7e6e5f (from https://pypi.python.org/simple/m2crypto/), version: 0.20.1
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.20.2.tar.gz#md5=6c24410410d6eb1920ea43f77a93613a (from https://pypi.python.org/simple/m2crypto/), version: 0.20.2
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.20.tar.gz#md5=43a4d958a6c892a37ca02ffcc650b66b (from https://pypi.python.org/simple/m2crypto/), version: 0.20
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.20beta1.tar.gz#md5=e1551fde39d75ebced9dd73b9a0ace50 (from https://pypi.python.org/simple/m2crypto/), version: 0.20beta1
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.21.1.tar.gz#md5=f93d8462ff7646397a9f77a2fe602d17 (from https://pypi.python.org/simple/m2crypto/), version: 0.21.1
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.21.tar.gz#md5=0057b9d04c821ebf3fdbadeb5a3acb36 (from https://pypi.python.org/simple/m2crypto/), version: 0.21
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.22.3.tar.gz#md5=573f21aaac7d5c9549798e72ffcefedd (from https://pypi.python.org/simple/m2crypto/), version: 0.22.3
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.22.4.tar.gz#md5=4998e9a27f90ad5ab98b77000f1c5f69 (from https://pypi.python.org/simple/m2crypto/), version: 0.22.4
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.22.5.tar.gz#md5=f84eb07aa1687f39bc26ee7b1ba5a105 (from https://pypi.python.org/simple/m2crypto/), version: 0.22.5
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.22.6rc1.tar.gz#md5=3c689818e435789da406eb59bed8f2fb (from https://pypi.python.org/simple/m2crypto/), version: 0.22.6rc1
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.22.6rc2.tar.gz#md5=019802df9507447c580ac2e015ea53d5 (from https://pypi.python.org/simple/m2crypto/), version: 0.22.6rc2
    Found link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.22.6rc3.tar.gz#md5=c650e0f6958d9e1ccb73a0369fbf23c8 (from https://pypi.python.org/simple/m2crypto/), version: 0.22.6rc3
    Found link https://pypi.python.org/packages/source/M/M2Crypto/m2crypto-0.15.tar.gz#md5=6a31501dc11cdfd9380ec4a18d461fd9 (from https://pypi.python.org/simple/m2crypto/), version: 0.15
    Found link https://pypi.python.org/packages/source/M/M2Crypto/m2crypto-0.16.tar.gz#md5=6fc06583a2be56fc2a46872a0540d78e (from https://pypi.python.org/simple/m2crypto/), version: 0.16
    Found link https://pypi.python.org/packages/source/M/M2Crypto/m2crypto-0.18.1.tar.gz#md5=c6e8fa402d920da08b0459dd5755a386 (from https://pypi.python.org/simple/m2crypto/), version: 0.18.1
    Found link https://pypi.python.org/packages/source/M/M2Crypto/m2crypto-0.18.2.tar.gz#md5=445dce53fcfc7ec8f6fd31f54da8a067 (from https://pypi.python.org/simple/m2crypto/), version: 0.18.2
    Found link https://pypi.python.org/packages/source/M/M2Crypto/m2crypto-0.18.tar.gz#md5=4e5432d08fd50287b80ac2237f01bda3 (from https://pypi.python.org/simple/m2crypto/), version: 0.18
  Ignoring link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.20beta1.tar.gz#md5=e1551fde39d75ebced9dd73b9a0ace50 (from https://pypi.python.org/simple/m2crypto/), version 0.20beta1 is a pre-release (use --pre to allow).
  Ignoring link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.22.6rc1.tar.gz#md5=3c689818e435789da406eb59bed8f2fb (from https://pypi.python.org/simple/m2crypto/), version 0.22.6rc1 is a pre-release (use --pre to allow).
  Ignoring link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.22.6rc2.tar.gz#md5=019802df9507447c580ac2e015ea53d5 (from https://pypi.python.org/simple/m2crypto/), version 0.22.6rc2 is a pre-release (use --pre to allow).
  Ignoring link https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.22.6rc3.tar.gz#md5=c650e0f6958d9e1ccb73a0369fbf23c8 (from https://pypi.python.org/simple/m2crypto/), version 0.22.6rc3 is a pre-release (use --pre to allow).
  Using version 0.22.5 (newest of versions: 0.22.5, 0.22.4, 0.22.3, 0.21.1, 0.21, 0.20.2, 0.20.1, 0.20, 0.19.1, 0.19, 0.18.2, 0.18.1, 0.18, 0.17, 0.16, 0.15)
  Downloading from URL https://pypi.python.org/packages/source/M/M2Crypto/M2Crypto-0.22.5.tar.gz#md5=f84eb07aa1687f39bc26ee7b1ba5a105 (from https://pypi.python.org/simple/m2crypto/)
  Running setup.py (path:/tmp/pip-build-_oTf56/M2Crypto/setup.py) egg_info for package M2Crypto
    running egg_info
    creating pip-egg-info/M2Crypto.egg-info
    writing pip-egg-info/M2Crypto.egg-info/PKG-INFO
    writing top-level names to pip-egg-info/M2Crypto.egg-info/top_level.txt
    writing dependency_links to pip-egg-info/M2Crypto.egg-info/dependency_links.txt
    writing manifest file 'pip-egg-info/M2Crypto.egg-info/SOURCES.txt'
    warning: manifest_maker: standard file '-c' not found

    reading manifest file 'pip-egg-info/M2Crypto.egg-info/SOURCES.txt'
    reading manifest template 'MANIFEST.in'
    warning: no previously-included files found matching 'M2Crypto/_m2crypto.py'
    writing manifest file 'pip-egg-info/M2Crypto.egg-info/SOURCES.txt'
  Source in /tmp/pip-build-_oTf56/M2Crypto has version 0.22.5, which satisfies requirement M2Crypto (from python-u2flib-server)
Requirement already satisfied (use --upgrade to upgrade): pyasn1>=0.1.7 in /usr/lib/python2.7/dist-packages (from python-u2flib-server)
Requirement already satisfied (use --upgrade to upgrade): pyasn1-modules in /usr/lib/python2.7/dist-packages (from python-u2flib-server)
Installing collected packages: M2Crypto
  Running setup.py install for M2Crypto
    Running command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-_oTf56/M2Crypto/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-W6QvT3-record/install-record.txt --single-version-externally-managed --compile
    running install
    running build
    running build_py
    creating build
    creating build/lib.linux-x86_64-2.7
    creating build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/util.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/threading.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/EVP.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/ftpslib.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/DSA.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/m2xmlrpclib.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/m2.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/callback.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/BN.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/SMIME.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/Rand.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/AuthCookie.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/RC4.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/ASN1.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/Err.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/BIO.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/m2urllib2.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/EC.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/RSA.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/m2urllib.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/X509.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/Engine.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/__init__.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/httpslib.py -> build/lib.linux-x86_64-2.7/M2Crypto
    copying M2Crypto/DH.py -> build/lib.linux-x86_64-2.7/M2Crypto
    creating build/lib.linux-x86_64-2.7/M2Crypto/SSL
    copying M2Crypto/SSL/cb.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
    copying M2Crypto/SSL/Session.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
    copying M2Crypto/SSL/SSLServer.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
    copying M2Crypto/SSL/Cipher.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
    copying M2Crypto/SSL/Connection.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
    copying M2Crypto/SSL/Checker.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
    copying M2Crypto/SSL/Context.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
    copying M2Crypto/SSL/TwistedProtocolWrapper.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
    copying M2Crypto/SSL/__init__.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
    copying M2Crypto/SSL/ssl_dispatcher.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
    copying M2Crypto/SSL/timeout.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL
    creating build/lib.linux-x86_64-2.7/M2Crypto/PGP
    copying M2Crypto/PGP/constants.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
    copying M2Crypto/PGP/PublicKeyRing.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
    copying M2Crypto/PGP/PublicKey.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
    copying M2Crypto/PGP/packet.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
    copying M2Crypto/PGP/RSA.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
    copying M2Crypto/PGP/__init__.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP
    running build_ext
    building 'M2Crypto.__m2crypto' extension
    swigging SWIG/_m2crypto.i to SWIG/_m2crypto_wrap.c
    swig -python -I/usr/include/python2.7 -I/usr/include -includeall -modern -builtin -outdir build/lib.linux-x86_64-2.7/M2Crypto -o SWIG/_m2crypto_wrap.c SWIG/_m2crypto.i
    SWIG/_evp.i:12: Error: Unable to find 'openssl/opensslconf.h'
    SWIG/_ec.i:7: Error: Unable to find 'openssl/opensslconf.h'
    error: command 'swig' failed with exit status 1
    Complete output from command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-_oTf56/M2Crypto/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-W6QvT3-record/install-record.txt --single-version-externally-managed --compile:
    running install

running build

running build_py

creating build

creating build/lib.linux-x86_64-2.7

creating build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/util.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/threading.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/EVP.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/ftpslib.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/DSA.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/m2xmlrpclib.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/m2.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/callback.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/BN.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/SMIME.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/Rand.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/AuthCookie.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/RC4.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/ASN1.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/Err.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/BIO.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/m2urllib2.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/EC.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/RSA.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/m2urllib.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/X509.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/Engine.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/__init__.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/httpslib.py -> build/lib.linux-x86_64-2.7/M2Crypto

copying M2Crypto/DH.py -> build/lib.linux-x86_64-2.7/M2Crypto

creating build/lib.linux-x86_64-2.7/M2Crypto/SSL

copying M2Crypto/SSL/cb.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL

copying M2Crypto/SSL/Session.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL

copying M2Crypto/SSL/SSLServer.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL

copying M2Crypto/SSL/Cipher.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL

copying M2Crypto/SSL/Connection.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL

copying M2Crypto/SSL/Checker.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL

copying M2Crypto/SSL/Context.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL

copying M2Crypto/SSL/TwistedProtocolWrapper.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL

copying M2Crypto/SSL/__init__.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL

copying M2Crypto/SSL/ssl_dispatcher.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL

copying M2Crypto/SSL/timeout.py -> build/lib.linux-x86_64-2.7/M2Crypto/SSL

creating build/lib.linux-x86_64-2.7/M2Crypto/PGP

copying M2Crypto/PGP/constants.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP

copying M2Crypto/PGP/PublicKeyRing.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP

copying M2Crypto/PGP/PublicKey.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP

copying M2Crypto/PGP/packet.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP

copying M2Crypto/PGP/RSA.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP

copying M2Crypto/PGP/__init__.py -> build/lib.linux-x86_64-2.7/M2Crypto/PGP

running build_ext

building 'M2Crypto.__m2crypto' extension

swigging SWIG/_m2crypto.i to SWIG/_m2crypto_wrap.c

swig -python -I/usr/include/python2.7 -I/usr/include -includeall -modern -builtin -outdir build/lib.linux-x86_64-2.7/M2Crypto -o SWIG/_m2crypto_wrap.c SWIG/_m2crypto.i

SWIG/_evp.i:12: Error: Unable to find 'openssl/opensslconf.h'

SWIG/_ec.i:7: Error: Unable to find 'openssl/opensslconf.h'

error: command 'swig' failed with exit status 1

----------------------------------------
Cleaning up...
Command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-_oTf56/M2Crypto/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-W6QvT3-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /tmp/pip-build-_oTf56/M2Crypto
Exception information:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/pip/basecommand.py", line 122, in main
    status = self.run(options, args)
  File "/usr/lib/python2.7/dist-packages/pip/commands/install.py", line 295, in run
    requirement_set.install(install_options, global_options, root=options.root_path)
  File "/usr/lib/python2.7/dist-packages/pip/req.py", line 1436, in install
    requirement.install(install_options, global_options, *args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/pip/req.py", line 707, in install
    cwd=self.source_dir, filter_stdout=self._filter_install, show_stdout=False)
  File "/usr/lib/python2.7/dist-packages/pip/util.py", line 716, in call_subprocess
    % (command_desc, proc.returncode, cwd))
InstallationError: Command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-_oTf56/M2Crypto/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-W6QvT3-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /tmp/pip-build-_oTf56/M2Crypto

I've gotten this error with SWIG 2.0 and 3.0.
The SWIG 2.0 was on my Debian server, Python 2.7 default, with libssl-dev installed.
The SWIG 3.0 was on my Arch home laptop, Python 3.5 default, with openssl installed.

Broken example

Just a heads up:

The Registration example at https://developers.yubico.com/python-u2flib-server/ fails at u2f.Register because the challenges differ (or at least that's the case using https://github.com/tstranex/u2f).

The example data in question is:

$ curl http://localhost:8081/enroll
{"authenticateRequests": [], "registerRequests": [{"challenge": "9s80ruHc6q9shJM5WLfOmz-ejb_Rm8dmWCnOvgZ2ovw", "version": "U2F_V2", "appId": "http://localhost:8081"}]}

$ curl http://localhost:8081/bind -d'data={"clientData": "eyJvcmlnaW4iOiAiaHR0cDovL2xvY2FsaG9zdDo4MDgxIiwgImNoYWxsZW5nZSI6ICJEMnB6VFBaYTdicTY5QUJ1aUdRSUxvOXpjc1RVUlAyNlJMaWZUeUNraWxjIiwgInR5cCI6ICJuYXZpZ2F0b3IuaWQuZmluaXNoRW5yb2xsbWVudCJ9", "registrationData": "BQSivQtJ6-lAgZ2qQ0aUGLEiJSRoLWUSGcmMO8C-GuibA0-xTvmuQfTqKyFJZWOUjGzEIgF4xV6gJ6itcagsyuUWQEQh9noDSu-WtzTOMhK_lKHxwHtQgJHCkzs4mukfpf310K5Dq9k6zBNtZ2RMBWgJhI7hJo4JiFn3k2GUNLwKZpwwggGHMIIBLqADAgECAgkAmb7osQyi7BwwCQYHKoZIzj0EATAhMR8wHQYDVQQDDBZZdWJpY28gVTJGIFNvZnQgRGV2aWNlMB4XDTEzMDcxNzE0MjEwM1oXDTE2MDcxNjE0MjEwM1owITEfMB0GA1UEAwwWWXViaWNvIFUyRiBTb2Z0IERldmljZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDvhl91zfpg9n7DeCedcQ8gGXUnemiXoi-JEAxz-EIhkVsMPAyzhtJZ4V3CqMZ-MOUgICt2aMxacMX9cIa8dgS2jUDBOMB0GA1UdDgQWBBQNqL-TV04iaO6mS5tjGE6ShfexnjAfBgNVHSMEGDAWgBQNqL-TV04iaO6mS5tjGE6ShfexnjAMBgNVHRMEBTADAQH_MAkGByqGSM49BAEDSAAwRQIgXJWZdbvOWdhVaG7IJtn44o21Kmi8EHsDk4cAfnZ0r38CIQD6ZPi3Pl4lXxbY7BXFyrpkiOvCpdyNdLLYbSTbvIBQOTBFAiEA1uwJKNez6_BHdA2d-DPmRFJj19biYNkhN86SFH5Z_lYCICld2L3ZAVsm_uNFRt13_N9dlhGu50pb1ql8-_3_p5v1"}'
true

It is possible I have misunderstood the example, but I was able to make u2f.Register (in golang) work as expected for a project of mine (demo) using known-data. You can reproduce the issue by checking out https://github.com/brianmhunt/aeu2f-go/blob/master/register_test.go, and updating the data with the test-data with the example above (or alternatively going backtracking through the commit history).

I have not tried the Authentication example.

Cheers.

TypeError: initializer for ctype 'char' must be a bytes of length 1, not int

I'm getting an error when calling complete_register:

Traceback (most recent call last):
  ...
  File "django-u2f/django_u2f/views.py", line 127, in form_valid
    device, attestation_cert = u2f.complete_register(challenge, response)
  File "u2flib_server/u2f_v2.py", line 208, in complete_register
    response.registrationData
  File "/home/gavin/.virtualenvs/lottery/lib/python3.5/site-packages/u2flib_server/u2f_v2.py", line 89, in __init__
    self.certificate = self._fixsig(certificate_from_der(data))
  File "u2flib_server/u2f_v2.py", line 111, in _fixsig
    cert = certificate_from_der(der)
  File "u2flib_server/utils.py", line 47, in certificate_from_der
    return x509.load_der_x509_certificate(der, default_backend())
  File "cryptography/x509/base.py", line 32, in load_der_x509_certificate
    return backend.load_der_x509_certificate(data)
  File "cryptography/hazmat/backends/multibackend.py", line 334, in load_der_x509_certificate
    return b.load_der_x509_certificate(data)
  File "cryptography/hazmat/backends/openssl/backend.py", line 1193, in load_der_x509_certificate
    mem_bio = self._bytes_to_bio(data)
  File "cryptography/hazmat/backends/openssl/backend.py", line 477, in _bytes_to_bio
    data_char_p = self._ffi.new("char[]", data)
TypeError: initializer for ctype 'char' must be a bytes of length 1, not int

This is on python 3.5. I'm not sure whether this should be reported here or in cryptography.

Looks like the problem might be in RawRegistrationResponse._fixsig. It calls list() on a bytestring to convert it to a list of integers, but never converts the list back to a bytestring. This patch does "fix" the issue, but I don't know if it's the correct solution and probably doesn't work on python 2:

diff --git a/u2flib_server/u2f_v2.py b/u2flib_server/u2f_v2.py
index 52793bf..3851871 100644
--- a/u2flib_server/u2f_v2.py
+++ b/u2flib_server/u2f_v2.py
@@ -107,8 +107,8 @@ class RawRegistrationResponse(object):

         if subject in FIXSIG:  # Set unused bits in signature to 0
             der = list(cert.public_bytes(Encoding.DER))
-            der[-257] = b'\x00'
-            cert = certificate_from_der(der)
+            der[-257] = 0
+            cert = certificate_from_der(bytes(der))
         return cert

     def serialize(self):

Standalone

We should think about how to make a U2F server standalone from yubiauth. I know there is an example but it should be fleshed out a bit more and documented.

Add code documentation

I would like to implement this package in a Django package. Therefore I would like to know the workings of the package but there is not much no documentation in the files. Is it possible for you to add some?

Keep up the good work!

Encoding problem for long random passwords

Url: http://demo.yubico.com/u2f?tab=register

 Traceback (most recent call last):
  File "/root/python-u2flib-server-demo/examples/yubiauth_server.py", line 118, in __call__
    password = request.params['password']
  File "/usr/lib/python2.7/dist-packages/webob/multidict.py", line 312, in __getitem__
    return self._decode_value(self.multi.__getitem__(self._encode_key(key)))
  File "/usr/lib/python2.7/dist-packages/webob/multidict.py", line 301, in _decode_value
    value = value.decode(self.encoding, self.errors)
  File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xbd in position 12: invalid start byte

Note this was rendered to screen; this occured using a 128char output for the password as follows.

pwgen -cnsy1 128

sG0hdZ5Op,L5%bDf@xh9Fp-lJd5-~!&D~X0C~h=];*.}0i5U7n2z#jj8?QncGr[qR@c%e<#GKb@YLK*34QQFN$4BfynM8:IU08Zt+M3M@ltDpUC-s4a~xvv#+^p!=+OC

>>> passwd = """sG0hdZ5Op,L5%bDf@xh9Fp-lJd5-~!&D~X0C~h=];*.}0i5U7n2z#jj8?QncGr[qR@c%e<#GKb@YLK*34QQFN$4BfynM8:IU08Zt+M3M@ltDpUC-s4a~xvv#+^p!=+OC"""
>>> passwd[12]
'%'

Seems there's some issue encoding issue around the % char once passed to the backend.

Can't install from source

pip install -e ~/python-u2flib-server

    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 20, in <module>
      File "python-u2flib-server/setup.py", line 28, in <module>
        from u2flib_server.yubicommon.setup import setup
    ImportError: No module named yubicommon.setup

    ----------------------------------------

`_parse_tlv_size` when tlv[1] <= 128

I am running through implementing a u2f server in elixir and have been using this library as a guide.
I have a question about the following line of code: _parse_tlv_size

I am bit new to DER encoding, but I have found the following link to be useful

After going through the implementation I don't quite understand why n_bytes is being initialized to 1 instead of 0. When the value of the length triplet is 128 or less, shouldn't we just have an offset of 2 bytes (1 for tag and 1 for length) with the value being calculated based on the second byte? Perhaps I am misunderstanding something, but I was curious as to why an additional byte was necessary.

DeprecationWarning for verifier

Using this (in a 3rd party lib) I get two DeprecationWarning messages:

/home/user/django-u2f/venv/lib/python3.5/site-packages/u2flib_server/model.py:178: CryptographyDeprecationWarning: signer and verifier have been deprecated. Please use sign and verify instead.
  verifier = pubkey.verifier(self.signature, ec.ECDSA(hashes.SHA256()))

/home/user/django-u2f/venv/lib/python3.5/site-packages/u2flib_server/model.py:210: CryptographyDeprecationWarning: signer and verifier have been deprecated. Please use sign and verify instead.
  verifier = pubkey.verifier(self.signature, ec.ECDSA(hashes.SHA256()))

Exception on demo site

I just tried out a yubikey device on this demo site: https://demo.yubico.com/u2f?tab=register

Registration failed with this error:
Traceback (most recent call last):
File "/root/python-u2flib-server-demo/examples/yubiauth_server.py", line 161, in call
raise Exception("FIDO Client error: %s" % error)
Exception: FIDO Client error: 1 (OTHER ERROR)

It shouldn't raise an exception for any client input, right? Let me know if this is the right place for the bug. I'm using Chromium on Lubuntu 16.04, if that helps.

Tests are broken on TravisCI under PyPy

TravisCI has PyPy 2.5.0 installed. As of python-u2flib-server 4.0.0 we will depend on Cryptography 1.2+, which in turn requires PyPy 2.6.0+. So even if our code is bug free TravisCI reports failure - since it can't install the dependencies, e.g. https://travis-ci.org/moreati/python-u2flib-server/jobs/111979422.

The Cryptography project gets around this by using pyenv to install a more recent version of PyPy. e.g. https://github.com/pyca/cryptography/blob/master/.travis/.

We could do the same, or wait for TravisCI to upgrade

Exception handling in u2flib

Calling verify_authenticate / complete_register can raise a bunch of different exceptions.

Here are some examples:

>>> from u2flib_server.u2f_v2 import start_authenticate, complete_register
>>> start_authenticate({})
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/Users/andreas/code/x/venv-2.7/lib/python2.7/site-packages/u2flib_server/u2f_v2.py", line 228, in start_authenticate
    appId=device.appId,
  File "/Users/andreas/code/x/venv-2.7/lib/python2.7/site-packages/u2flib_server/jsapi.py", line 68, in __getattr__
    (type(self).__name__, key))
AttributeError: 'DeviceRegistration' object has no attribute 'appId'
>>> start_authenticate('{}')
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/Users/andreas/code/x/venv-2.7/lib/python2.7/site-packages/u2flib_server/u2f_v2.py", line 228, in start_authenticate
    appId=device.appId,
  File "/Users/andreas/code/x/venv-2.7/lib/python2.7/site-packages/u2flib_server/jsapi.py", line 68, in __getattr__
    (type(self).__name__, key))
AttributeError: 'DeviceRegistration' object has no attribute 'appId'
>>> start_authenticate('banana')
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/Users/andreas/code/x/venv-2.7/lib/python2.7/site-packages/u2flib_server/u2f_v2.py", line 221, in start_authenticate
    device = DeviceRegistration.wrap(device)
  File "/Users/andreas/code/x/venv-2.7/lib/python2.7/site-packages/u2flib_server/jsapi.py", line 76, in wrap
    return data if isinstance(data, cls) else cls(data)
  File "/Users/andreas/code/x/venv-2.7/lib/python2.7/site-packages/u2flib_server/jsapi.py", line 57, in __init__
    self.update(json.loads(data.decode('utf-8')))
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 366, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 384, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded
>>>

When a signature check fails, cryptography.exceptions.InvalidSignature is raised. How are users supposed to know to catch an exception from the underlying cryptography library?

Given that this is the reference implementation of U2F for Python servers and this is security sensitive, exceptions and error conditions should be handled better and clearer. The example server can be crashed in a number of way by provided user input. The examples should be using best practices and be crash free.

My proposal: u2flib should define its own exceptions "U2FError" and could have different subclasses to classify input formatting errors "U2FMalformedInput" from signature errors "U2FSignatureError". Any exceptions that is raised from invoking u2flib that is not a "U2FError" should be treated as a bug.

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.