Esempio n. 1
0
    def make_credential(self, pin=None):
        rp = {"id": self.host, "name": "example site"}
        user = {"id": self.user_id, "name": "example user"}
        challenge = b"Y2hhbGxlbmdl"
        options = PublicKeyCredentialCreationOptions(
            rp,
            user,
            challenge,
            [{
                "type": "public-key",
                "alg": -8
            }, {
                "type": "public-key",
                "alg": -7
            }],
        )
        attest, data = self.client.make_credential(options, pin=pin)
        try:
            attest.verify(data.hash)
        except AttributeError:
            verifier = Attestation.for_type(attest.fmt)
            verifier().verify(attest.att_statement, attest.auth_data,
                              data.hash)
        print("Register valid")
        x5c = attest.att_statement["x5c"][0]
        cert = x509.load_der_x509_certificate(x5c, default_backend())

        return cert
Esempio n. 2
0
    def test_make_credential_ctap1(self):
        dev = mock.Mock()
        dev.capabilities = 0  # No CTAP2
        client = Fido2Client(dev, APP_ID)

        ctap1_mock = mock.MagicMock()
        ctap1_mock.get_version.return_value = "U2F_V2"
        ctap1_mock.register.return_value = REG_DATA
        client._backend.ctap1 = ctap1_mock

        response = client.make_credential(
            PublicKeyCredentialCreationOptions(rp, user, challenge, [{
                "type": "public-key",
                "alg": -7
            }]))

        self.assertIsInstance(response.attestation_object, AttestationObject)
        self.assertIsInstance(response.client_data, CollectedClientData)
        client_data = response.client_data

        ctap1_mock.register.assert_called_with(client_data.hash,
                                               sha256(rp["id"].encode()))

        self.assertEqual(client_data.origin, APP_ID)
        self.assertEqual(client_data.type, "webauthn.create")
        self.assertEqual(client_data.challenge, challenge)

        self.assertEqual(response.attestation_object.fmt, "fido-u2f")
Esempio n. 3
0
    def test_make_credential_ctap1(self):
        dev = mock.Mock()
        dev.capabilities = 0  # No CTAP2
        client = Fido2Client(dev, APP_ID)

        client.ctap1 = mock.MagicMock()
        client.ctap1.get_version.return_value = "U2F_V2"
        client.ctap1.register.return_value = REG_DATA

        attestation, client_data = client.make_credential(
            PublicKeyCredentialCreationOptions(rp, user, challenge, [{
                "type": "public-key",
                "alg": -7
            }]))

        self.assertIsInstance(attestation, AttestationObject)
        self.assertIsInstance(client_data, ClientData)

        client.ctap1.register.assert_called_with(client_data.hash,
                                                 sha256(rp["id"].encode()))

        self.assertEqual(client_data.get("origin"), APP_ID)
        self.assertEqual(client_data.get("type"), "webauthn.create")
        self.assertEqual(client_data.challenge, challenge)

        self.assertEqual(attestation.fmt, "fido-u2f")
Esempio n. 4
0
    def test_make_credential_existing_key(self, PatchedCTAP2):
        dev = mock.Mock()
        dev.capabilities = CAPABILITY.CBOR
        ctap2 = mock.MagicMock()
        ctap2.get_info.return_value = Info(_INFO_NO_PIN)
        ctap2.make_credential.side_effect = CtapError(
            CtapError.ERR.CREDENTIAL_EXCLUDED)
        PatchedCTAP2.return_value = ctap2
        client = Fido2Client(dev, APP_ID)

        try:
            client.make_credential(
                PublicKeyCredentialCreationOptions(
                    rp,
                    user,
                    challenge,
                    [{
                        "type": "public-key",
                        "alg": -7
                    }],
                    authenticator_selection={
                        "userVerification": "discouraged"
                    },
                ))
            self.fail("make_credential did not raise error")
        except ClientError as e:
            self.assertEqual(e.code, ClientError.ERR.DEVICE_INELIGIBLE)

        ctap2.get_info.assert_called_with()
        ctap2.make_credential.assert_called_once()
Esempio n. 5
0
    def _make_credential(self, client, user):
        pub_key_cred_params = [PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, cose.ES256.ALGORITHM)]
        options = PublicKeyCredentialCreationOptions(self._rp, user, self._challenge, pub_key_cred_params,
                                                     timeout=self._timeout_ms)

        pin = self._get_pin_from_client(client)
        self._attestation, self._client_data = client.make_credential(options, event=self._event,
                                                                      on_keepalive=self.on_keepalive,
                                                                      pin=pin)
        self._event.set()
Esempio n. 6
0
    def gen_key(self):
        name = input('Real name: ')
        email = input('Email address: ')
        username = "******".format(name, email)
        created = int(time.time())
        rp = {"id": RP_ID, "name": "OpenPGP"}
        user = {"id": struct.pack('>I', created), "name": username}
        challenge = secrets.token_bytes(32)
        options = PublicKeyCredentialCreationOptions(
            rp,
            user,
            challenge, [{
                "type": "public-key",
                "alg": -8
            }, {
                "type": "public-key",
                "alg": -7
            }],
            authenticator_selection={"require_resident_key": True})

        attestation_object, client_data = self.client.make_credential(
            options, pin=self.pin)
        statement = attestation_object.att_statement
        auth_data = attestation_object.auth_data
        attestation = Attestation.for_type("packed")()
        attestation.verify(statement, auth_data, client_data.hash)

        cred_id = auth_data.credential_data.credential_id
        pubkey_x = auth_data.credential_data.public_key[-2]
        pubkey_y = auth_data.credential_data.public_key[-3]

        pubkey = (pubkey_x, pubkey_y)
        pubkey_pkt = self._pubkey_packet(pubkey, created)
        userid_pkt = self._userid_packet(username)
        fp = self._fingerprint(pubkey_pkt)
        key_id = fp[-8:]
        print("Key ID: {}".format(key_id.hex().upper()))
        print("Key fingerprint: {}\n".format(fp.hex().upper()))

        hashed_prefix = b'\x99\x00\x52' + pubkey_pkt[2:]
        hashed_prefix += b'\xb4' + struct.pack(
            '>I',
            len(userid_pkt) - 2) + userid_pkt[2:]
        hashed_subpkts = [
            SubPacket(0x21, b'\x04' + fp),
            SubPacket(0x1B, b'\x03'),  # key flags
            SubPacket(0x02, struct.pack('>I', created))
        ]
        unhashed_subpkts = [SubPacket(0x10, key_id)]  # issuer
        sig_pkt = self._signature_packet_key(cred_id, hashed_prefix,
                                             hashed_subpkts, unhashed_subpkts)
        armored = self._ascii_armor(pubkey_pkt + userid_pkt + sig_pkt)
        print(
            '-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n{}-----END PGP PUBLIC KEY BLOCK-----'
            .format(armored))
Esempio n. 7
0
    def test_creation_options(self):
        o = PublicKeyCredentialCreationOptions(
            {"id": "example.com", "name": "Example"},
            {"id": b"user_id", "name": "A. User"},
            b"request_challenge",
            [{"type": "public-key", "alg": -7}],
            10000,
            [{"type": "public-key", "id": b"credential_id"}],
            {
                "authenticatorAttachment": "platform",
                "requireResidentKey": True,
                "userVerification": "required",
            },
            "direct",
        )
        self.assertEqual(o.rp, {"id": "example.com", "name": "Example"})
        self.assertEqual(o.user, {"id": b"user_id", "name": "A. User"})
        self.assertIsNone(o.extensions)

        o = PublicKeyCredentialCreationOptions(
            {"id": "example.com", "name": "Example"},
            {"id": b"user_id", "name": "A. User"},
            b"request_challenge",
            [{"type": "public-key", "alg": -7}],
        )
        self.assertIsNone(o.timeout)
        self.assertIsNone(o.authenticator_selection)
        self.assertIsNone(o.attestation)

        with self.assertRaises(ValueError):
            PublicKeyCredentialCreationOptions(
                {"id": "example.com", "name": "Example"},
                {"id": b"user_id", "name": "A. User"},
                b"request_challenge",
                [{"type": "public-key", "alg": -7}],
                attestation="invalid",
            )
Esempio n. 8
0
    def test_make_credential_ctap2(self, PatchedCtap2):
        dev = mock.Mock()
        dev.capabilities = CAPABILITY.CBOR
        ctap2 = mock.MagicMock()
        ctap2.get_info.return_value = Info.from_dict(cbor.decode(_INFO_NO_PIN))
        ctap2.info = ctap2.get_info()
        ctap2.make_credential.return_value = AttestationResponse.from_dict(
            cbor.decode(_MC_RESP))
        PatchedCtap2.return_value = ctap2
        client = Fido2Client(dev, APP_ID)

        response = client.make_credential(
            PublicKeyCredentialCreationOptions(
                rp,
                user,
                challenge,
                [{
                    "type": "public-key",
                    "alg": -7
                }],
                timeout=1000,
                authenticator_selection={"userVerification": "discouraged"},
            ))

        self.assertIsInstance(response.attestation_object, AttestationObject)
        self.assertIsInstance(response.client_data, CollectedClientData)

        ctap2.make_credential.assert_called_with(
            response.client_data.hash,
            rp,
            user,
            [{
                "type": "public-key",
                "alg": -7
            }],
            None,
            None,
            None,
            None,
            None,
            event=mock.ANY,
            on_keepalive=mock.ANY,
        )

        self.assertEqual(response.client_data.origin, APP_ID)
        self.assertEqual(response.client_data.type, "webauthn.create")
        self.assertEqual(response.client_data.challenge, challenge)
    def make_credential(self, options, **kwargs):
        """Creates a credential.

        :param options: PublicKeyCredentialCreationOptions data.
        :param pin: (optional) Used if PIN verification is required.
        :param threading.Event event: (optional) Signal to abort the operation.
        :param on_keepalive: (optional) function to call with CTAP status updates.
        """

        options = PublicKeyCredentialCreationOptions._wrap(options)
        pin = kwargs.get("pin")
        event = kwargs.get("event", Event())
        if options.timeout:
            timer = Timer(options.timeout / 1000, event.set)
            timer.daemon = True
            timer.start()

        self._verify_rp_id(options.rp.id)

        client_data = self._build_client_data(WEBAUTHN_TYPE.MAKE_CREDENTIAL,
                                              options.challenge)

        selection = options.authenticator_selection or AuthenticatorSelectionCriteria(
        )
        try:
            return (
                self._do_make_credential(
                    client_data,
                    options.rp,
                    options.user,
                    options.pub_key_cred_params,
                    options.exclude_credentials,
                    options.extensions,
                    selection.require_resident_key,
                    self._get_ctap_uv(selection.user_verification, pin
                                      is not None),
                    pin,
                    event,
                    kwargs.get("on_keepalive"),
                ),
                client_data,
            )
        except CtapError as e:
            raise _ctap2client_err(e)
        finally:
            if options.timeout:
                timer.cancel()
Esempio n. 10
0
    def test_make_credential_ctap2(self, PatchedCTAP2):
        dev = mock.Mock()
        dev.capabilities = CAPABILITY.CBOR
        ctap2 = mock.MagicMock()
        ctap2.get_info.return_value = Info(_INFO_NO_PIN)
        ctap2.make_credential.return_value = AttestationObject(_MC_RESP)
        PatchedCTAP2.return_value = ctap2
        client = Fido2Client(dev, APP_ID)

        attestation, client_data = client.make_credential(
            PublicKeyCredentialCreationOptions(
                rp,
                user,
                challenge,
                [{
                    "type": "public-key",
                    "alg": -7
                }],
                timeout=1000,
                authenticator_selection={"userVerification": "discouraged"},
            ))

        self.assertIsInstance(attestation, AttestationObject)
        self.assertIsInstance(client_data, ClientData)

        ctap2.get_info.assert_called_with()
        ctap2.make_credential.assert_called_with(
            client_data.hash,
            rp,
            user,
            [{
                "type": "public-key",
                "alg": -7
            }],
            None,
            None,
            None,
            None,
            None,
            mock.ANY,
            None,
        )

        self.assertEqual(client_data.get("origin"), APP_ID)
        self.assertEqual(client_data.get("type"), "webauthn.create")
        self.assertEqual(client_data.challenge, challenge)
Esempio n. 11
0
def make_credential(
    host="solokeys.dev",
    user_id="they",
    serial=None,
    pin=None,
    prompt="Touch your authenticator to generate a credential...",
    output=True,
    udp=False,
):
    user_id = user_id.encode()
    client = solo.client.find(solo_serial=serial, udp=udp).client

    rp = {"id": host, "name": "Example RP"}
    client.host = host
    client.origin = f"https://{client.host}"
    client.user_id = user_id
    user = {"id": user_id, "name": "A. User"}
    challenge = secrets.token_bytes(32)

    if prompt:
        print(prompt)

    hmac_ext = HmacSecretExtension(client.ctap2)

    options = PublicKeyCredentialCreationOptions(
        rp,
        user,
        challenge,
        [{
            "type": "public-key",
            "alg": -8
        }, {
            "type": "public-key",
            "alg": -7
        }],
        extensions=hmac_ext.create_dict(),
    )

    attestation_object, client_data = client.make_credential(options, pin=pin)

    credential = attestation_object.auth_data.credential_data
    credential_id = credential.credential_id
    if output:
        print(credential_id.hex())

    return credential_id
Esempio n. 12
0
 def test_make_credential_wrong_app_id(self, PatchedCTAP2):
     dev = mock.Mock()
     dev.capabilities = CAPABILITY.CBOR
     ctap2 = mock.MagicMock()
     ctap2.get_info.return_value = Info(_INFO_NO_PIN)
     PatchedCTAP2.return_value = ctap2
     client = Fido2Client(dev, APP_ID)
     try:
         client.make_credential(
             PublicKeyCredentialCreationOptions(
                 {"id": "bar.example.com", "name": "Invalid RP"},
                 user,
                 challenge,
                 [{"type": "public-key", "alg": -7}],
             )
         )
         self.fail("make_credential did not raise error")
     except ClientError as e:
         self.assertEqual(e.code, ClientError.ERR.BAD_REQUEST)
Esempio n. 13
0
def create_credential(client, token, host="localhost", silent=False):
    rp = {"id": host, "name": "TOTP Token"}
    user = {"id": token.encode(), "name": "%s token" % token}

    challenge = secrets.token_bytes(32)

    options = PublicKeyCredentialCreationOptions(
        rp,
        user,
        challenge,
        [{"type": "public-key", "alg": -8}, {"type": "public-key", "alg": -7}],
        extensions={"hmacCreateSecret": True},
        authenticator_selection={"require_resident_key": True},
    )

    if not silent:
      print("Please press security key to create new credential")

    result = client.make_credential(options)

    credential = result.attestation_object.auth_data.credential_data
    credential_id = credential.credential_id

    return credential_id.hex()