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 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 _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 _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