def forwards_func(apps, schema_editor): # We get the model from the versioned app registry; U2FDevice = apps.get_model("sso_auth", "U2FDevice") db_alias = schema_editor.connection.alias for d in U2FDevice.objects.using(db_alias).all(): credential_data = AttestedCredentialData.from_ctap1(websafe_decode(d.key_handle), websafe_decode(d.public_key_old)) d.public_key = websafe_encode(cbor.encode(credential_data.public_key)) d.aaguid = websafe_encode(credential_data.aaguid) d.credential_id = websafe_encode(credential_data.credential_id) d.save()
def complete_reg(request): try: data = cbor.loads(request.body)[0] client_data = ClientData(data['clientDataJSON']) att_obj = AttestationObject((data['attestationObject'])) server = getServer() auth_data = server.register_complete(request.session['fido_state'], client_data, att_obj) encoded = websafe_encode(auth_data.credential_data) uk = User_Keys() uk.username = request.user.username uk.properties = { "device": encoded, "type": att_obj.fmt, } uk.key_type = "FIDO2" uk.save() return HttpResponse(simplejson.dumps({'status': 'OK'})) except Exception as exp: from raven.contrib.django.raven_compat.models import client import traceback client.captureException() return HttpResponse( simplejson.dumps({ 'status': 'ERR', "message": "Error on server, please try again later" }))
def register_complete(name, **kwargs): """ Complete registration of the new key and save it under a given name Variables: name => Name of the token Arguments: data => Response to the enroll challenge Data Block: None Result example: { "success": True } """ uname = kwargs['user']['uname'] user = STORAGE.user.get(uname, as_obj=False) data = cbor.decode(bytes(request.json)) client_data = ClientData(data['clientDataJSON']) att_obj = AttestationObject(data['attestationObject']) auth_data = server.register_complete(session.pop('state', None), client_data, att_obj) security_tokens = user.get('security_tokens', {}) if name in security_tokens: return make_api_response({'success': False}, err="A token with this name already exist", status_code=400) security_tokens[name] = websafe_encode(auth_data.credential_data) user['security_tokens'] = security_tokens return make_api_response({"success": STORAGE.user.save(uname, user)})
def complete_reg(request): """Completes the registeration, called by API""" try: data = cbor.decode(request.body) client_data = ClientData(data['clientDataJSON']) att_obj = AttestationObject((data['attestationObject'])) server = getServer() auth_data = server.register_complete(request.session['fido_state'], client_data, att_obj) encoded = websafe_encode(auth_data.credential_data) uk = User_Keys() uk.username = request.user.username uk.properties = { "device": encoded, "type": att_obj.fmt, } uk.owned_by_enterprise = getattr(settings, "MFA_OWNED_BY_ENTERPRISE", False) uk.key_type = "FIDO2" uk.save() return HttpResponse(simplejson.dumps({'status': 'OK'})) except Exception as exp: try: from raven.contrib.django.raven_compat.models import client client.captureException() except: pass return HttpResponse( simplejson.dumps({ 'status': 'ERR', "message": "Error on server, please try again later" }))
def attest(rp, user, credset, attset): credset_dict = credset_decode(credset) attset_dict = attset_decode(attset) server = cred_server(rp) challenge = cred_challenge(rp, user) create_options, state = server.register_begin(user, challenge=challenge) client_data = ClientData.build( type=WEBAUTHN_TYPE.MAKE_CREDENTIAL, origin=fidosig_origin(rp['id']), challenge=websafe_encode(challenge), clientExtensions={}, ) for credential_id, public_key in credset_dict.items(): if credential_id not in attset_dict: raise Exception('Missing attestation') attestation_object = attset_dict[credential_id] auth_data = server.register_complete(state, client_data, attestation_object) if auth_data.credential_data.credential_id != credential_id: raise Exception('Wrong credential id') if auth_data.credential_data.public_key != public_key: raise Exception('Wrong public key')
def complete_reg(request): try: data = cbor.decode(request.body) client_data = ClientData(data['clientDataJSON']) att_obj = AttestationObject((data['attestationObject'])) server = get_server() auth_data = server.register_complete(request.session['fido_state'], client_data, att_obj) encoded = websafe_encode(auth_data.credential_data) key = UserKey.objects.create( user=request.user, properties={ "device": encoded, "type": att_obj.fmt, "domain": request.get_host(), }, key_type=KEY_TYPE_FIDO2, ) write_session(request, key) messages.success(request, 'FIDO2 Token added!') return JsonResponse({'status': 'OK'}) except Exception: logger.exception("Error completing FIDO2 registration.") return JsonResponse({ 'status': 'ERR', "message": "Error on server, please try again later", })
def _get_assertion_request( rp_id: str = 'pasten.com', client_data: Optional[ClientData] = None, allowed_cred_ids: Optional[List[bytes]] = None, user_verification_required=False, ) -> dict: client_data = client_data or ClientData.build( typ=WEBAUTHN_TYPE.GET_ASSERTION, origin=rp_id, challenge=websafe_encode(b'pasten-challenge'), ) req = { CtapGetAssertionRequest.RP_ID_KEY: rp_id, CtapGetAssertionRequest.CLIENT_DATA_HASH_KEY: client_data.hash, } if user_verification_required: req[CtapGetAssertionRequest.OPTIONS_KEY] = { CtapOptions.USER_VERIFICATION: True } if allowed_cred_ids: req[CtapGetAssertionRequest.ALLOW_LIST_KEY] = [ PublicKeyCredentialDescriptor( PublicKeyCredentialType.PUBLIC_KEY, cred_id ) for cred_id in allowed_cred_ids ] return req
def authenticate_complete(cls, response_data, state_data, user): response = cbor.decode(b64decode(response_data)) state = signing.loads(state_data, salt=U2FDevice.WEB_AUTHN_SALT) credential_id = response["credentialId"] client_data = ClientData(response["clientDataJSON"]) auth_data = AuthenticatorData(response["authenticatorData"]) signature = response["signature"] credentials = U2FDevice.credentials(user) cred = cls.server.authenticate_complete( state, credentials, credential_id, client_data, auth_data, signature, ) credential_id = websafe_encode(cred.credential_id) device = U2FDevice.objects.get(user=user, credential_id=credential_id) if auth_data.counter <= device.counter: # verify counter is increasing raise ValueError( f"login counter is not increasing. {auth_data.counter} <= {device.counter} " ) device.last_used = timezone.now() device.counter = auth_data.counter device.save(update_fields=["last_used", "counter"]) return device
def complete_reg(request): try: data = cbor.decode(request.body) client_data = ClientData(data['clientDataJSON']) att_obj = AttestationObject((data['attestationObject'])) server = get_server() auth_data = server.register_complete(request.session['fido_state'], client_data, att_obj) encoded = websafe_encode(auth_data.credential_data) UserKey.objects.create( username=request.user.get_username(), properties={ "device": encoded, "type": att_obj.fmt }, key_type="FIDO2", ) return JsonResponse({'status': 'OK'}) except: return JsonResponse({ 'status': 'ERR', "message": "Error on server, please try again later", })
def test_websafe_encode(self): self.assertEqual(websafe_encode(b""), "") self.assertEqual(websafe_encode(b"f"), "Zg") self.assertEqual(websafe_encode(b"fo"), "Zm8") self.assertEqual(websafe_encode(b"foo"), "Zm9v") self.assertEqual(websafe_encode(b"foob"), "Zm9vYg") self.assertEqual(websafe_encode(b"fooba"), "Zm9vYmE") self.assertEqual(websafe_encode(b"foobar"), "Zm9vYmFy")
def test_websafe_encode(self): self.assertEqual(websafe_encode(b''), u'') self.assertEqual(websafe_encode(b'f'), u'Zg') self.assertEqual(websafe_encode(b'fo'), u'Zm8') self.assertEqual(websafe_encode(b'foo'), u'Zm9v') self.assertEqual(websafe_encode(b'foob'), u'Zm9vYg') self.assertEqual(websafe_encode(b'fooba'), u'Zm9vYmE') self.assertEqual(websafe_encode(b'foobar'), u'Zm9vYmFy')
def _get_assertions(seed, rp, options): client_data = ClientData.build( type=WEBAUTHN_TYPE.GET_ASSERTION, origin=fidosig_origin(rp['id']), challenge=websafe_encode(options.challenge), clientExtensions={}, ) client_data_hash = client_data.hash rp_id_hash = sha256(rp['id'].encode('utf8')).digest() assertions = [ _get_assertion_1(seed, rp_id_hash, descriptor, client_data_hash) for descriptor in options.allow_credentials ] return assertions, client_data
def do_register_user(user, rp_id, resident_key=False): """ FIDO2 registration process :param user: The user to register :param rp_id: Relying Party identifier :param resident_key: Boolean indicating whether or not to store a resident key :return: Newly created credentials """ # begin registration relying_part = RelyingParty(rp_id) server = Fido2Server(relying_part) registration_data, state = server.register_begin(user) # make credential dev = next(CtapHidDevice.list_devices(), None) if not dev: print('No FIDO device found') sys.exit(1) client = Fido2Client(dev, 'https://' + rp_id) rp = {'id': rp_id, 'name': rp_id} challenge = websafe_encode(registration_data['publicKey']['challenge']) if resident_key: user['name'] = "." user_string = "(id: {0})".format(user['id'].hex()) else: user_string = "(name: {0}, display name: {1})".format( user['name'], user['displayName']) print("\nRegistration request for user: "******"From service: (Address: {0}, Name: {1})".format(rp['id'], rp['name'])) print('Touch your authenticator device now to consent to registration...\n') try: attestation_object, client_data = client.make_credential( rp, user, challenge, rk=resident_key) except Exception as e: print("Registration failed") raise e # complete registration registration_data = server.register_complete(state, client_data, attestation_object) credential = registration_data.credential_data print("Registration complete") return credential
def register_complete(cls, name, response_data, state_data, user): data = cbor.decode(b64decode(response_data)) state = signing.loads(state_data, salt=U2FDevice.WEB_AUTHN_SALT) client_data = ClientData(data["clientDataJSON"]) att_obj = AttestationObject(data["attestationObject"]) logger.debug("clientData", client_data) logger.debug("AttestationObject:", att_obj) auth_data = cls.server.register_complete(state, client_data, att_obj) logger.debug(auth_data) public_key = websafe_encode( cbor.encode(auth_data.credential_data.public_key)) aaguid = websafe_encode(auth_data.credential_data.aaguid) credential_id = websafe_encode(auth_data.credential_data.credential_id) device = U2FDevice.objects.create(name=name, user=user, public_key=public_key, credential_id=credential_id, aaguid=aaguid, confirmed=True, version="fido2") return device
def get_access_key(rpi_username, verify=True, uv=False): auth_begin_response = requests.request( 'GET', AUTHENTICATE_BEGIN_URI.format(rpi_username), verify=verify) assert auth_begin_response.status_code == 200 cookies = auth_begin_response.cookies auth_begin_response_dict = cbor.decode(auth_begin_response.content) urlparse_result = urlparse(AUTHENTICATE_BEGIN_URI) scheme = urlparse_result.scheme origin = urlparse_result.hostname rp_id = auth_begin_response_dict['publicKey']['rpId'] challenge = websafe_encode( auth_begin_response_dict['publicKey']['challenge']) allow_list = auth_begin_response_dict['publicKey']['allowCredentials'] fido2_client = create_fido2_client('{}://{}'.format(scheme, origin)) assertions, client_data = fido2_client.get_assertion(rp_id, challenge, allow_list, uv=uv) access_key = websafe_encode(assertions[0].signature) auth_complete_payload = dict( credentialId=assertions[0].credential['id'], clientDataJSON=client_data, authenticatorData=assertions[0].auth_data, signature=assertions[0].signature, ) auth_complete_payload_encoded = cbor.encode(auth_complete_payload) auth_complete_response = requests.post( AUTHENTICATE_COMPLETE_URI.format(rpi_username), data=auth_complete_payload_encoded, verify=verify, cookies=cookies, ) auth_complete_response_decoded = cbor.decode( auth_complete_response.content) assert auth_complete_response_decoded.get('status') == 'OK' return access_key
def u2f_begin(): registration_data, state = server.register_begin( { 'id': b'user_id', 'name': 'a_user', 'displayName': 'A. User', 'icon': 'https://example.com/image.png' }, credentials) session['state'] = state print('\n\n\n\n') print(registration_data) print('\n\n\n\n') return cbor.dumps( websafe_encode(registration_data['publicKey']['challenge']))
def u2f_begin(): registration_data, state = server.register_begin( { "id": b"user_id", "name": "a_user", "displayName": "A. User", }, credentials, ) session["state"] = state print("\n\n\n\n") print(registration_data) print("\n\n\n\n") return cbor.encode( websafe_encode(registration_data["publicKey"]["challenge"]))
def register_complete(): data = cbor.decode(flask.request.get_data()) client_data = ClientData(data["clientDataJSON"]) att_obj = AttestationObject(data["attestationObject"]) # print("clientData", client_data) # print("AttestationObject:", att_obj) auth_data = server.register_complete(flask.session["state"], client_data, att_obj) flask.session["credentials"].append(auth_data.credential_data) encoded = websafe_encode(auth_data.credential_data) users = cube.load_file("users") users[flask.session["account"]]["yubi"] = encoded cube.dump_file(users, "users") # print("REGISTERED CREDENTIAL:", auth_data.credential_data) return cbor.encode({"status": "OK"})
def generate_assertion_request(self, user_id=None): """ Generate an assertion request :param user_id: The user id :return: The FIDO2AssertionRequest message """ user_credentials = self._get_user_credentials(user_id) request_options, self._auth_state = \ self._server.authenticate_begin(user_credentials) # check request options request_options = request_options['publicKey'] challenge = websafe_encode(request_options['challenge']) timeout = None rp_id = None allow_credentials = None user_verification = None extensions = None eph_user_name_server_share = None # fill optional information if 'timeout' in request_options: timeout = request_options['timeout'] if 'rpId' in request_options: rp_id = request_options['rpId'] if 'allowCredentials' in request_options: allow_credentials = request_options['allowCredentials'] self._allow_credentials = allow_credentials if 'userVerification' in request_options: user_verification = request_options['userVerification'].value if 'extensions' in request_options: extensions = request_options['extensions'] if self.mode == FIDO2Mode.fido2_with_name and \ self.pre_share_eph_user_name: eph_user_name_server_share = bytearray(urandom(32)) self._eph_user_name_server_share = \ eph_user_name_server_share fido2_assertion_request = FIDO2AssertionRequest().create( challenge, timeout, rp_id, allow_credentials, user_verification, extensions, eph_user_name_server_share) return fido2_assertion_request
def _get_make_credential_request( algorithm: int = cose.RS256.ALGORITHM, user_id: str = '*****@*****.**', user_name: str = 'pasten', rp_id: str = 'pasten.com', rp_name: str = 'Pasten LTD', client_data: Optional[ClientData] = None, excluded_cred_ids: Optional[List[bytes]] = None, ) -> dict: client_data = client_data or ClientData.build( typ=WEBAUTHN_TYPE.MAKE_CREDENTIAL, origin=rp_id, challenge=websafe_encode(b'pasten-challenge'), ) req = { CtapMakeCredentialRequest.CLIENT_DATA_HASH_KEY: hashlib.sha256( client_data ).digest(), CtapMakeCredentialRequest.RP_KEY: PublicKeyCredentialRpEntity( rp_id, rp_name ), CtapMakeCredentialRequest.USER_KEY: PublicKeyCredentialUserEntity( user_id, user_name ), CtapMakeCredentialRequest.PUBLIC_KEY_CREDENTIAL_PARAMS_KEY: [ PublicKeyCredentialParameters( PublicKeyCredentialType.PUBLIC_KEY, algorithm ) ], } if excluded_cred_ids: req[CtapMakeCredentialRequest.EXCLUDE_LIST_KEY] = [ PublicKeyCredentialDescriptor( PublicKeyCredentialType.PUBLIC_KEY, cred_id ) for cred_id in excluded_cred_ids ] return req
def _verify_1(rp, header, msg, credential_id, public_key, sig): randomization = sig[SIGENTRY.RANDOMIZATION] auth_data = AuthenticatorData(sig[SIGENTRY.AUTH_DATA]) signature = sig[SIGENTRY.SIGNATURE] server = sign_server(rp) challenge = sign_challenge(randomization, header, msg) request_options, state = server.authenticate_begin( user_verification=UserVerificationRequirement.DISCOURAGED, challenge=challenge, ) client_data = ClientData.build( type=WEBAUTHN_TYPE.GET_ASSERTION, origin=fidosig_origin(rp['id']), challenge=websafe_encode(challenge), clientExtensions={}, ) credentials = [AttestedCredentialData.create( b'\0' * 16, credential_id, public_key )] try: server.authenticate_complete( state, credentials, credential_id, client_data, auth_data, signature, ) except InvalidSignature: return False return True
def test_websafe_encode_unicode(self): self.assertEqual(websafe_encode(u''), u'') self.assertEqual(websafe_encode(u'foobar'), u'Zm9vYmFy')
# id stored in DB, queried via user name user = {"id": b"user_id", "name": "A. User"} # Prepare parameters for makeCredential create_options, state = server.register_begin( user, user_verification=uv, authenticator_attachment="cross-platform") # Create a credential if use_prompt: print("\nTouch your authenticator device now...\n") attestation_object, client_data = client.make_credential( create_options["publicKey"], pin=pin) # Complete registration auth_data = server.register_complete(state, client_data, attestation_object) credentials = [auth_data.credential_data] # Credentials is what needs to be stored print("New credential created!") # https://github.com/Yubico/python-fido2/issues/31 encoded = websafe_encode(auth_data.credential_data) # Store this value print("Credentials: ") print(auth_data.credential_data) print() print("Encoded: ") print(encoded) #credential_data = AttestedCredentialData(websafe_decode(encoded)) # Restored from serialized value
def credential(self, cred): self.cred_data = websafe_encode(cred) self.cred_id = websafe_encode(cred.credential_id)
for dev in enumerate_devices(): client = Fido2Client(dev, "https://secrez.io") if HmacSecretExtension.NAME in client.info.extensions: break else: print("No Authenticator with the HmacSecret extension found!") sys.exit(1) rp = {"id": "secrez.io", "name": "secrez"} user = {"id": bytes(user_id, encoding='utf-8'), "name": user_name} challenge = bytes(randomString(12), encoding='utf-8') hmac_ext = HmacSecretExtension(client.ctap2) attestation_object, client_data = client.make_credential({ "rp": rp, "user": user, "challenge": challenge, "pubKeyCredParams": [{ "type": "public-key", "alg": -7 }], "extensions": hmac_ext.create_dict(), }) credential = attestation_object.auth_data.credential_data print(websafe_encode(credential))
attestation_object, client_data = client.make_credential( create_options["publicKey"], pin=pin) # Complete registration auth_data = server.register_complete(state, client_data, attestation_object) credentials = [auth_data.credential_data] # Credentials is what needs to be stored print("New credential created!") print("CLIENT DATA:", client_data) print("ATTESTATION OBJECT:", attestation_object) print() print("CREDENTIAL DATA:", auth_data.credential_data) encoded = websafe_encode(auth_data.credential_data) creds2 = [AttestedCredentialData(websafe_decode(encoded))] # Prepare parameters for getAssertion #request_options, state = server.authenticate_begin(credentials, user_verification=uv) request_options, state = server.authenticate_begin(creds2, user_verification=uv) # Authenticate the credential if use_prompt: print("\nTouch your authenticator device now...\n") assertions, client_data = client.get_assertion(request_options["publicKey"], pin=pin) assertion = assertions[
"login": "******", "firstName": "Bob", "timeZone": "America/Los_Angeles", }, "id": "XXXIDXXX", } }, "sessionToken": "XXXTOKENXXX", } CREDENTIAL_ID_STR = b"ababababababa" CREDENTIAL_ID_ENC = "YWJhYmFiYWJhYmFiYQ==" CREDENTIAL_ID_DEC = base64.urlsafe_b64decode(CREDENTIAL_ID_ENC) NONCE_STR = b"anonce" NONCE_ENC = websafe_encode(NONCE_STR) CHALLENGE_RESPONSE = { "status": "MFA_CHALLENGE", "_embedded": { "factor": { "profile": { "credentialId": CREDENTIAL_ID_ENC, "authenticatorName": "yekibuy", }, "_embedded": { "challenge": { "challenge": NONCE_ENC, "extensions": {} } },