Beispiel #1
0
def _ctap2_enroll(dev, alg, application, user, pin, resident):
    """Enroll a new security key using CTAP version 2"""

    ctap2 = CTAP2(dev)

    application = application.decode('utf-8')
    rp = {'id': application, 'name': application}
    user = {'id': user.encode('utf-8'), 'name': user}
    key_params = [{'type': 'public-key', 'alg': alg}]
    options = {'rk': resident}

    if pin:
        pin_protocol = PinProtocolV1(ctap2)
        pin_token = pin_protocol.get_pin_token(pin)

        pin_version = pin_protocol.VERSION
        pin_auth = hmac.new(pin_token, _dummy_hash, sha256).digest()[:16]
    else:
        pin_version = None
        pin_auth = None

    cred = ctap2.make_credential(_dummy_hash,
                                 rp,
                                 user,
                                 key_params,
                                 options=options,
                                 pin_auth=pin_auth,
                                 pin_protocol=pin_version)
    cdata = cred.auth_data.credential_data

    return _decode_public_key(alg, cdata.public_key), cdata.credential_id
Beispiel #2
0
def get_assertion(ctap2: CTAP2, clientDataJSON_hash, allowList):
    return ctap2.get_assertions(
        RP_ID,
        clientDataJSON_hash,
        allowList,
        options={'up': False},
    )
    def test_get_info(self):
        ctap = CTAP2(mock.MagicMock())
        ctap.device.call.return_value = b'\0' + _INFO

        info = ctap.get_info()
        ctap.device.call.assert_called_with(0x10, b'\4', None, None)
        self.assertIsInstance(info, Info)
Beispiel #4
0
 def sign_hash(self, credential_id, dgst, pin):
     ctap2 = CTAP2(self.get_current_hid_device())
     client = self.get_current_fido_client()
     if pin:
         pin_token = client.client_pin.get_pin_token(pin)
         pin_auth = hmac_sha256(pin_token, dgst)[:16]
         return ctap2.send_cbor(
             0x50,
             {
                 1: dgst,
                 2: {
                     "id": credential_id,
                     "type": "public-key"
                 },
                 3: pin_auth
             },
         )
     else:
         return ctap2.send_cbor(0x50, {
             1: dgst,
             2: {
                 "id": credential_id,
                 "type": "public-key"
             }
         })
Beispiel #5
0
    def find_device(self, dev=None, solo_serial=None):
        if dev is None:
            devices = list(CtapHidDevice.list_devices())
            if solo_serial is not None:
                devices = [
                    d for d in devices
                    if d.descriptor["serial_number"] == solo_serial
                ]
            if len(devices) > 1:
                raise solo.exceptions.NonUniqueDeviceError
            if len(devices) == 0:
                raise RuntimeError("No FIDO device found")
            dev = devices[0]
        self.dev = dev

        self.ctap1 = CTAP1(dev)
        self.ctap2 = CTAP2(dev)
        try:
            self.client = Fido2Client(dev, self.origin)
        except CtapError:
            print("Not using FIDO2 interface.")
            self.client = None

        if self.exchange == self.exchange_hid:
            self.send_data_hid(CTAPHID.INIT,
                               "\x11\x11\x11\x11\x11\x11\x11\x11")

        return self.dev
Beispiel #6
0
    def test_send_cbor_ok(self):
        ctap = CTAP2(mock.MagicMock())
        ctap.device.call.return_value = b"\0" + cbor.encode({1: b"response"})

        self.assertEqual({1: b"response"}, ctap.send_cbor(2, b"foobar"))
        ctap.device.call.assert_called_with(0x10,
                                            b"\2" + cbor.encode(b"foobar"),
                                            mock.ANY, None)
    def test_send_cbor_ok(self):
        ctap = CTAP2(mock.MagicMock())
        ctap.device.call.return_value = b'\0' + cbor.encode({1: b'response'})

        self.assertEqual({1: b'response'}, ctap.send_cbor(2, b'foobar'))
        ctap.device.call.assert_called_with(0x10,
                                            b'\2' + cbor.encode(b'foobar'),
                                            None, None)
Beispiel #8
0
    def find_device(self,):
        dev = next(CtapHidDevice.list_devices(), None)
        if not dev:
            raise RuntimeError('No FIDO device found')
        self.dev = dev
        self.ctap1 = CTAP1(dev)
        self.ctap2 = CTAP2(dev)
        self.client = Fido2Client(dev, self.origin)

        if self.exchange == self.exchange_hid:
            self.send_data_hid(CTAPHID.INIT, '\x11\x11\x11\x11\x11\x11\x11\x11')
Beispiel #9
0
def _ctap2_sign(dev, message_hash, application, key_handle, touch_required):
    """Sign a message with a security key using CTAP version 2"""

    ctap2 = CTAP2(dev)

    application = application.decode('utf-8')
    allow_creds = [{'type': 'public-key', 'id': key_handle}]
    options = {'up': touch_required}

    assertion = ctap2.get_assertions(application,
                                     message_hash,
                                     allow_creds,
                                     options=options)[0]

    auth_data = assertion.auth_data

    return auth_data.flags, auth_data.counter, assertion.signature
Beispiel #10
0
    def test_get_assertion(self):
        ctap = CTAP2(mock.MagicMock())
        ctap.device.call.return_value = b'\0' + _GA_RESP

        resp = ctap.get_assertion(1, 2)
        ctap.device.call.assert_called_with(0x10, b'\2' + cbor.encode({
            1: 1,
            2: 2
        }), None, None)

        self.assertIsInstance(resp, AssertionResponse)
        self.assertEqual(resp, _GA_RESP)
        self.assertEqual(resp.credential, _CRED)
        self.assertEqual(resp.auth_data, _AUTH_DATA_GA)
        self.assertEqual(resp.signature, _SIGNATURE)
        self.assertIsNone(resp.user)
        self.assertIsNone(resp.number_of_credentials)
    def uv_supported(device):
        """
        Determine whether user verification is supported by the device.
        :param device: The device to check user verification capability for.
        :return: True if user verification is supported, False otherwise
        """
        try:
            ctap2 = CTAP2(device)
        except ValueError:
            return False

        try:
            info = ctap2.get_info()
        except OSError:
            return False

        return bool('uv' in info.options and info.options['uv'])
    def __init__(self, device, origin, verify=verify_rp_id):
        super(Fido2Client, self).__init__(origin, verify)

        self.ctap1_poll_delay = 0.25
        try:
            self.ctap2 = CTAP2(device)
            self.info = self.ctap2.get_info()
            if PinProtocolV1.VERSION in self.info.pin_protocols:
                self.pin_protocol = PinProtocolV1(self.ctap2)
            else:
                self.pin_protocol = None
            self._do_make_credential = self._ctap2_make_credential
            self._do_get_assertion = self._ctap2_get_assertion
        except (ValueError, CtapError):
            self.ctap1 = CTAP1(device)
            self.info = _CTAP1_INFO
            self._do_make_credential = self._ctap1_make_credential
            self._do_get_assertion = self._ctap1_get_assertion
Beispiel #13
0
def sk_get_resident(application, user, pin):
    """Get keys resident on a security key"""

    app_hash = sha256(application).digest()
    result = []

    for dev in CtapHidDevice.list_devices():
        try:
            ctap2 = CTAP2(dev)

            pin_protocol = PinProtocolV1(ctap2)
            pin_token = pin_protocol.get_pin_token(pin)

            cred_mgmt = CredentialManagement(ctap2, pin_protocol.VERSION,
                                             pin_token)

            for cred in cred_mgmt.enumerate_creds(app_hash):
                name = cred[CredentialManagement.RESULT.USER]['name']

                if user and name != user:
                    continue

                cred_id = cred[CredentialManagement.RESULT.CREDENTIAL_ID]
                key_handle = cred_id['id']

                public_key = cred[CredentialManagement.RESULT.PUBLIC_KEY]
                alg = public_key[3]
                public_value = _decode_public_key(alg, public_key)

                result.append((alg, name, public_value, key_handle))
        except CtapError as exc:
            if exc.code == CtapError.ERR.NO_CREDENTIALS:
                continue
            elif exc.code == CtapError.ERR.PIN_INVALID:
                raise ValueError('Invalid PIN') from None
            elif exc.code == CtapError.ERR.PIN_NOT_SET:
                raise ValueError('PIN not set') from None
            else:
                raise ValueError(str(exc)) from None
        finally:
            dev.close()

    return result
Beispiel #14
0
    def test_make_credential(self):
        ctap = CTAP2(mock.MagicMock())
        ctap.device.call.return_value = b'\0' + _MC_RESP

        resp = ctap.make_credential(1, 2, 3, 4)
        ctap.device.call.assert_called_with(
            0x10, b'\1' + cbor.encode({
                1: 1,
                2: 2,
                3: 3,
                4: 4
            }), None, None)

        self.assertIsInstance(resp, AttestationObject)
        self.assertEqual(resp, _MC_RESP)
        self.assertEqual(resp.fmt, 'packed')
        self.assertEqual(resp.auth_data, _AUTH_DATA_MC)
        self.assertSetEqual(set(resp.att_statement.keys()),
                            {'alg', 'sig', 'x5c'})
Beispiel #15
0
    def test_make_credential(self):
        ctap = CTAP2(mock.MagicMock())
        ctap.device.call.return_value = b"\0" + _MC_RESP

        resp = ctap.make_credential(1, 2, 3, 4)
        ctap.device.call.assert_called_with(
            0x10, b"\1" + cbor.encode({
                1: 1,
                2: 2,
                3: 3,
                4: 4
            }), mock.ANY, None)

        self.assertIsInstance(resp, AttestationObject)
        self.assertEqual(resp, _MC_RESP)
        self.assertEqual(resp.fmt, "packed")
        self.assertEqual(resp.auth_data, _AUTH_DATA_MC)
        self.assertSetEqual(set(resp.att_statement.keys()),
                            {"alg", "sig", "x5c"})
Beispiel #16
0
    def find_device(self, dev=None, solo_serial: str = None):
        devices = []
        if dev is None:
            if solo_serial is not None:
                if solo_serial.startswith("device="):
                    solo_serial = solo_serial.split("=")[1]
                    dev = open_device(solo_serial)
                else:
                    devices = list(CtapHidDevice.list_devices())
                    devices = [
                        d for d in devices
                        if d.descriptor.serial_number == solo_serial
                    ]
            else:
                devices = list(CtapHidDevice.list_devices())
            if len(devices) > 1:
                raise pynitrokey.exceptions.NonUniqueDeviceError
            if len(devices) > 0:
                dev = devices[0]
        if dev is None:
            raise RuntimeError("No FIDO device found")
        self.dev = dev

        self.ctap1 = CTAP1(dev)

        try:
            self.ctap2: Optional[CTAP2] = CTAP2(dev)
        except CtapError as e:
            self.ctap2 = None

        try:
            self.client: Optional[Fido2Client] = Fido2Client(dev, self.origin)
        except CtapError:
            print("Not using FIDO2 interface.")
            self.client = None

        if self.exchange == self.exchange_hid:
            self.send_data_hid(CTAPHID.INIT,
                               "\x11\x11\x11\x11\x11\x11\x11\x11")

        return self.dev
Beispiel #17
0
def make_credential(ctap2: CTAP2, clientDataJSON_hash):
    att_obj = ctap2.make_credential(
        clientDataJSON_hash,
        {
            'id': RP_ID,
            'name': 'Test RP'
        },
        {
            'id': USER_ID,
            'name': '*****@*****.**',
            'displayName': 'Test'
        },
        [{
            'alg': -7,
            'type': 'public-key'
        }],
    )

    return {
        'id': att_obj.auth_data.credential_data.credential_id,
        'type': 'public-key'
    }
Beispiel #18
0
    def find_device(self, dev=None, solo_serial=None):
        if dev is None:
            devices = list(CtapHidDevice.list_devices())
            if solo_serial is not None:
                for d in devices:
                    if not hasattr(d, "serial_number"):
                        print(
                            "Currently serial numbers are not supported with current fido2 library.  Please upgrade: pip3 install fido2 --upgrade"
                        )
                        sys.exit(1)
                devices = [
                    d for d in devices
                    if d.descriptor.serial_number == solo_serial
                ]
            if len(devices) > 1:
                raise solo.exceptions.NonUniqueDeviceError
            if len(devices) == 0:
                raise RuntimeError("No FIDO device found")
            dev = devices[0]
        self.dev = dev

        self.ctap1 = CTAP1(dev)
        try:
            self.ctap2 = CTAP2(dev)
        except CtapError:
            self.ctap2 = None

        try:
            self.client = Fido2Client(dev, self.origin)
        except CtapError:
            print("Not using FIDO2 interface.")
            self.client = None

        if self.exchange == self.exchange_hid:
            self.send_data_hid(CTAPHID.INIT,
                               "\x11\x11\x11\x11\x11\x11\x11\x11")

        return self.dev
Beispiel #19
0
def create_ctap2_handle():
    for dev in CtapHidDevice.list_devices():
        return CTAP2(dev)
    print("No FIDO device found")
Beispiel #20
0
 def mock_ctap(self):
     device = mock.MagicMock()
     device.call.return_value = b"\0" + _INFO
     return CTAP2(device)
Beispiel #21
0
from fido2.hid import CtapHidDevice
from fido2.ctap2 import CTAP2


def get_device():
    devs = list(CtapHidDevice.list_devices())
    assert len(devs) == 1
    return devs[0]


if __name__ == '__main__':
    try:
        dev = get_device()
    except Exception:
        print("Unable to find authenticator")
        exit(-1)

    ctap = CTAP2(dev)
    try:
        ctap.reset()
        print("Device successfully reset")
    except Exception as e:
        print(e)
Beispiel #22
0
 def __init__(self, dev):
     origin = RP_ID
     self.client = Fido2Client(dev, origin, verify=verify_rp_id)
     self.ctap2 = CTAP2(dev)
     self.pin = os.getenv('SOLOPIN')
Beispiel #23
0
 def __init__(self, ctap_device):
     self.ctap = CTAP2(ctap_device)
     self.pin = ClientPin(self.ctap)
     self._info = self.ctap.get_info()
     self._pin = self._info.options["clientPin"]
Beispiel #24
0
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
"""
Connects to each attached FIDO device, and:
    1. If the device supports CBOR commands, perform a getInfo command.
    2. If the device supports WINK, perform the wink command.
"""
from __future__ import print_function, absolute_import, unicode_literals

from fido2.hid import CtapHidDevice, CAPABILITY
from fido2.ctap2 import CTAP2

for dev in CtapHidDevice.list_devices():
    print('CONNECT: %s' % dev)

    if dev.capabilities & CAPABILITY.CBOR:
        ctap2 = CTAP2(dev)
        info = ctap2.get_info()
        print('DEVICE INFO: %s' % info)
    else:
        print('Device does not support CBOR')

    if dev.capabilities & CAPABILITY.WINK:
        dev.wink()
        print('WINK sent!')
    else:
        print('Device does not support WINK')
Beispiel #25
0
 def __init__(self, driver):
     self.ctap = CTAP2(driver._dev)
     self.pin = PinProtocolV1(self.ctap)
     self._info = self.ctap.get_info()
     self._pin = self._info.options['clientPin']
Beispiel #26
0
 def cred_mgmt(self, pin):
     client = self.get_current_fido_client()
     token = client.client_pin.get_pin_token(pin)
     ctap2 = CTAP2(self.get_current_hid_device())
     return CredentialManagement(ctap2, client.client_pin.protocol, token)
Beispiel #27
0
 def program_kbd(self, cmd):
     ctap2 = CTAP2(self.get_current_hid_device())
     return ctap2.send_cbor(0x51, cmd)
Beispiel #28
0
 def reset(self, ):
     CTAP2(self.get_current_hid_device()).reset()