def test_auth_header_preparation(tag,
                                 auth_tag,
                                 id_nonce,
                                 initiator_key,
                                 auth_response_key,
                                 ephemeral_public_key):
    enr = ENR(
        sequence_number=1,
        signature=b"",
        kv_pairs={
            b"id": b"v4",
            b"secp256k1": b"\x02" * 33,
        }
    )
    message = PingMessage(
        request_id=5,
        enr_seq=enr.sequence_number,
    )
    id_nonce_signature = b"\x00" * 32

    packet = AuthHeaderPacket.prepare(
        tag=tag,
        auth_tag=auth_tag,
        id_nonce=id_nonce,
        message=message,
        initiator_key=initiator_key,
        id_nonce_signature=id_nonce_signature,
        auth_response_key=auth_response_key,
        enr=enr,
        ephemeral_public_key=ephemeral_public_key
    )

    assert packet.tag == tag
    assert packet.auth_header.auth_tag == auth_tag
    assert packet.auth_header.id_nonce == id_nonce
    assert packet.auth_header.auth_scheme_name == AUTH_SCHEME_NAME
    assert packet.auth_header.ephemeral_public_key == ephemeral_public_key

    decrypted_auth_response = aesgcm_decrypt(
        key=auth_response_key,
        nonce=ZERO_NONCE,
        cipher_text=packet.auth_header.encrypted_auth_response,
        authenticated_data=b"",
    )
    decoded_auth_response = rlp.decode(decrypted_auth_response)
    assert is_list_like(decoded_auth_response) and len(decoded_auth_response) == 3
    assert decoded_auth_response[0] == int_to_big_endian(AUTH_RESPONSE_VERSION)
    assert decoded_auth_response[1] == id_nonce_signature
    assert ENR.deserialize(decoded_auth_response[2]) == enr

    decrypted_message = aesgcm_decrypt(
        key=initiator_key,
        nonce=auth_tag,
        cipher_text=packet.encrypted_message,
        authenticated_data=tag,
    )
    assert decrypted_message[0] == message.message_type
    assert rlp.decode(decrypted_message[1:], PingMessage) == message
    def decrypt_auth_response(
            self, auth_response_key: AES128Key) -> Tuple[bytes, Optional[ENR]]:
        """Extract id nonce signature and optional ENR from auth header packet."""
        plain_text = aesgcm_decrypt(
            key=auth_response_key,
            nonce=ZERO_NONCE,
            cipher_text=self.auth_header.encrypted_auth_response,
            authenticated_data=b"",
        )

        try:
            decoded_rlp = rlp.decode(plain_text)
        except DecodingError:
            raise ValidationError(
                f"Auth response does not contain valid RLP: {encode_hex(plain_text)}"
            )

        if not is_list_like(decoded_rlp):
            raise ValidationError(
                f"Auth response contains bytes instead of list: {encode_hex(decoded_rlp)}"
            )

        if len(decoded_rlp) != 3:
            raise ValidationError(
                f"Auth response is a list of {len(decoded_rlp)} instead of three elements"
            )
        version_bytes, id_nonce_signature, serialized_enr = decoded_rlp

        if not is_bytes(version_bytes):
            raise ValidationError(
                f"Version is a list instead of big endian encoded integer: {version_bytes}"
            )
        version_int = big_endian_to_int(version_bytes)
        if version_int != AUTH_RESPONSE_VERSION:
            raise ValidationError(
                f"Expected auth response version {AUTH_RESPONSE_VERSION}, but got {version_int}"
            )

        if not is_bytes(id_nonce_signature):
            raise ValidationError(
                f"Id nonce signature is a list instead of bytes: {id_nonce_signature}"
            )

        if not is_list_like(serialized_enr):
            raise ValidationError(
                f"ENR is bytes instead of list: {encode_hex(serialized_enr)}")

        if len(serialized_enr) == 0:
            enr = None
        else:
            try:
                enr = ENR.deserialize(serialized_enr)
            except DeserializationError as error:
                raise ValidationError(
                    "ENR in auth response is not properly encoded") from error

        return id_nonce_signature, enr
示例#3
0
async def test_enr_response_handler_does_not_crash_on_invalid_responses():
    discovery = MockDiscoveryService([])
    token = b''
    invalid_enr = b'garbage'
    payload = [token, invalid_enr]
    await discovery.recv_enr_response(discovery.this_node, payload, b'')

    enr = ENRFactory()
    enr._kv_pairs.pop(b'secp256k1')
    with pytest.raises(ValidationError):
        ENR.deserialize(ENR.serialize(enr))
    payload = [token, ENR.serialize(enr)]
    await discovery.recv_enr_response(discovery.this_node, payload, b'')

    enr = ENRFactory()
    enr._signature = b'garbage'
    with pytest.raises(eth_keys.exceptions.ValidationError):
        enr.validate_signature()
    payload = [token, ENR.serialize(enr)]
    await discovery.recv_enr_response(discovery.this_node, payload, b'')