Raise HandshakeFailure in transport

Change the exception handling flow.
Raise `SecurityUpgradeFailure` in security_multistream.
This commit is contained in:
mhchia 2019-08-21 15:12:35 +08:00
parent 80452d9589
commit 3e04480d62
No known key found for this signature in database
GPG Key ID: 389EFBEA1362589A
6 changed files with 54 additions and 21 deletions

View File

@ -10,6 +10,7 @@ def pubkey_from_protobuf(pubkey_pb: protobuf.PublicKey) -> PublicKey:
# TODO: Test against secp256k1 keys
elif pubkey_pb.key_type == protobuf.Secp256k1:
return Secp256k1PublicKey.from_bytes(pubkey_pb.data)
# TODO: Support `Ed25519` and `ECDSA` in the future?
else:
raise ValueError(
f"unsupported key_type={pubkey_pb.key_type}, data={pubkey_pb.data!r}"

View File

@ -1,6 +1,8 @@
class ValidationError(Exception):
class BaseLibp2pError(Exception):
pass
class ValidationError(BaseLibp2pError):
"""
Raised when something does not pass a validation check.
"""
pass

View File

@ -6,7 +6,7 @@ from libp2p.peer.id import ID
from libp2p.security.base_session import BaseSession
from libp2p.security.base_transport import BaseSecureTransport
from libp2p.security.secure_conn_interface import ISecureConn
from libp2p.transport.exceptions import SecurityUpgradeFailure
from libp2p.transport.exceptions import HandshakeFailure
from libp2p.typing import TProtocol
from libp2p.utils import encode_fixedint_prefixed, read_fixedint_prefixed
@ -32,14 +32,14 @@ class InsecureSession(BaseSession):
# Verify if the given `pubkey` matches the given `peer_id`
try:
remote_pubkey = pubkey_from_protobuf(remote_msg.pubkey)
except ValueError as error:
raise SecurityUpgradeFailure(
f"unknown protocol of remote_msg.pubkey={remote_msg.pubkey}"
) from error
except ValueError:
raise HandshakeFailure(
f"unknown `key_type` of remote_msg.pubkey={remote_msg.pubkey}"
)
remote_peer_id = ID(remote_msg.id)
remote_peer_id_from_pubkey = ID.from_pubkey(remote_pubkey)
if remote_peer_id_from_pubkey != remote_peer_id:
raise SecurityUpgradeFailure(
raise HandshakeFailure(
"peer id and pubkey from the remote mismatch: "
f"remote_peer_id={remote_peer_id}, remote_pubkey={remote_pubkey}, "
f"remote_peer_id_from_pubkey={remote_peer_id_from_pubkey}"
@ -76,10 +76,9 @@ class InsecureTransport(BaseSecureTransport):
"""
session = InsecureSession(self, conn, peer_id)
await session.run_handshake()
# TODO: Check if `remote_public_key is not None`. If so, check if `session.remote_peer`
received_peer_id = session.get_remote_peer()
if received_peer_id != peer_id:
raise SecurityUpgradeFailure(
if session.remote_permanent_pubkey is not None and received_peer_id != peer_id:
raise HandshakeFailure(
"remote peer sent unexpected peer ID. "
f"expected={peer_id} received={received_peer_id}"
)

View File

@ -4,11 +4,15 @@ from typing import Mapping
from libp2p.network.connection.raw_connection_interface import IRawConnection
from libp2p.peer.id import ID
from libp2p.protocol_muxer.multiselect import Multiselect
from libp2p.protocol_muxer.multiselect_client import MultiselectClient
from libp2p.protocol_muxer.multiselect import Multiselect, MultiselectError
from libp2p.protocol_muxer.multiselect_client import (
MultiselectClient,
MultiselectClientError,
)
from libp2p.protocol_muxer.multiselect_communicator import RawConnectionCommunicator
from libp2p.security.secure_conn_interface import ISecureConn
from libp2p.security.secure_transport_interface import ISecureTransport
from libp2p.transport.exceptions import HandshakeFailure, SecurityUpgradeFailure
from libp2p.typing import TProtocol
@ -63,8 +67,18 @@ class SecurityMultistream(ABC):
for an inbound connection (i.e. we are not the initiator)
:return: secure connection object (that implements secure_conn_interface)
"""
try:
transport = await self.select_transport(conn, False)
except MultiselectError as error:
raise SecurityUpgradeFailure(
"failed to negotiate the secure protocol"
) from error
try:
secure_conn = await transport.secure_inbound(conn)
except HandshakeFailure as error:
raise SecurityUpgradeFailure(
"failed to secure the inbound transport"
) from error
return secure_conn
async def secure_outbound(self, conn: IRawConnection, peer_id: ID) -> ISecureConn:
@ -73,8 +87,18 @@ class SecurityMultistream(ABC):
for an inbound connection (i.e. we are the initiator)
:return: secure connection object (that implements secure_conn_interface)
"""
try:
transport = await self.select_transport(conn, True)
except MultiselectClientError as error:
raise SecurityUpgradeFailure(
"failed to negotiate the secure protocol"
) from error
try:
secure_conn = await transport.secure_outbound(conn, peer_id)
except HandshakeFailure as error:
raise SecurityUpgradeFailure(
"failed to secure the outbound transport"
) from error
return secure_conn
async def select_transport(

View File

@ -1,7 +1,14 @@
from libp2p.exceptions import BaseLibp2pError
# TODO: Add `BaseLibp2pError` and `UpgradeFailure` can inherit from it?
class UpgradeFailure(Exception):
class UpgradeFailure(BaseLibp2pError):
pass
class SecurityUpgradeFailure(UpgradeFailure):
pass
class HandshakeFailure(BaseLibp2pError):
pass

View File

@ -4,9 +4,9 @@ import pytest
from libp2p import new_node
from libp2p.crypto.rsa import create_new_key_pair
from libp2p.protocol_muxer.multiselect_client import MultiselectClientError
from libp2p.security.insecure.transport import InsecureSession, InsecureTransport
from libp2p.security.simple.transport import SimpleSecurityTransport
from libp2p.transport.exceptions import SecurityUpgradeFailure
from tests.configs import LISTEN_MADDR
from tests.utils import cleanup, connect
@ -161,7 +161,7 @@ async def test_multiple_security_none_the_same_fails():
def assertion_func(_):
assert False
with pytest.raises(MultiselectClientError):
with pytest.raises(SecurityUpgradeFailure):
await perform_simple_test(
assertion_func, transports_for_initiator, transports_for_noninitiator
)