1# Copyright (c) 2018 Yubico AB 2# All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or 5# without modification, are permitted provided that the following 6# conditions are met: 7# 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above 11# copyright notice, this list of conditions and the following 12# disclaimer in the documentation and/or other materials provided 13# with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26# POSSIBILITY OF SUCH DAMAGE. 27 28from __future__ import absolute_import, unicode_literals 29 30from .base import ( 31 Attestation, 32 AttestationType, 33 AttestationResult, 34 InvalidSignature, 35 catch_builtins, 36) 37from ..cose import ES256 38 39from cryptography import x509 40from cryptography.hazmat.backends import default_backend 41from cryptography.exceptions import InvalidSignature as _InvalidSignature 42 43 44class FidoU2FAttestation(Attestation): 45 FORMAT = "fido-u2f" 46 47 @catch_builtins 48 def verify(self, statement, auth_data, client_data_hash): 49 cd = auth_data.credential_data 50 pk = b"\x04" + cd.public_key[-2] + cd.public_key[-3] 51 x5c = statement["x5c"] 52 FidoU2FAttestation.verify_signature( 53 auth_data.rp_id_hash, 54 client_data_hash, 55 cd.credential_id, 56 pk, 57 x5c[0], 58 statement["sig"], 59 ) 60 return AttestationResult(AttestationType.BASIC, x5c) 61 62 @staticmethod 63 def verify_signature( 64 app_param, client_param, key_handle, public_key, cert_bytes, signature 65 ): 66 m = b"\0" + app_param + client_param + key_handle + public_key 67 cert = x509.load_der_x509_certificate(cert_bytes, default_backend()) 68 try: 69 ES256.from_cryptography_key(cert.public_key()).verify(m, signature) 70 except _InvalidSignature: 71 raise InvalidSignature() 72