Apply PR feedback:
move signature validation logic into signature validator
This commit is contained in:
parent
1c54c38ca7
commit
658a0ae156
|
@ -17,7 +17,6 @@ import base58
|
||||||
from lru import LRU
|
from lru import LRU
|
||||||
|
|
||||||
from libp2p.crypto.keys import PrivateKey
|
from libp2p.crypto.keys import PrivateKey
|
||||||
from libp2p.crypto.serialization import deserialize_public_key
|
|
||||||
from libp2p.exceptions import ParseError, ValidationError
|
from libp2p.exceptions import ParseError, ValidationError
|
||||||
from libp2p.host.host_interface import IHost
|
from libp2p.host.host_interface import IHost
|
||||||
from libp2p.io.exceptions import IncompleteReadError
|
from libp2p.io.exceptions import IncompleteReadError
|
||||||
|
@ -30,7 +29,7 @@ from libp2p.utils import encode_varint_prefixed, read_varint_prefixed_bytes
|
||||||
|
|
||||||
from .pb import rpc_pb2
|
from .pb import rpc_pb2
|
||||||
from .pubsub_notifee import PubsubNotifee
|
from .pubsub_notifee import PubsubNotifee
|
||||||
from .validators import signature_validator
|
from .validators import PUBSUB_SIGNING_PREFIX, signature_validator
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .pubsub_router_interface import IPubsubRouter # noqa: F401
|
from .pubsub_router_interface import IPubsubRouter # noqa: F401
|
||||||
|
@ -49,8 +48,6 @@ SyncValidatorFn = Callable[[ID, rpc_pb2.Message], bool]
|
||||||
AsyncValidatorFn = Callable[[ID, rpc_pb2.Message], Awaitable[bool]]
|
AsyncValidatorFn = Callable[[ID, rpc_pb2.Message], Awaitable[bool]]
|
||||||
ValidatorFn = Union[SyncValidatorFn, AsyncValidatorFn]
|
ValidatorFn = Union[SyncValidatorFn, AsyncValidatorFn]
|
||||||
|
|
||||||
PUBSUB_SIGNING_PREFIX = "libp2p-pubsub:"
|
|
||||||
|
|
||||||
|
|
||||||
class TopicValidator(NamedTuple):
|
class TopicValidator(NamedTuple):
|
||||||
validator: ValidatorFn
|
validator: ValidatorFn
|
||||||
|
@ -534,32 +531,10 @@ class Pubsub:
|
||||||
if self._is_msg_seen(msg):
|
if self._is_msg_seen(msg):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check if signing is required and if so signature should be attached.
|
# Check if signing is required and if so validate the signature
|
||||||
if self.strict_signing:
|
if self.strict_signing:
|
||||||
if msg.signature == b"":
|
|
||||||
logger.debug("Reject because no signature attached for msg: %s", msg)
|
|
||||||
return
|
|
||||||
# Validate if message sender matches message signer,
|
|
||||||
# i.e., check if `msg.key` matches `msg.from_id`
|
|
||||||
msg_pubkey = deserialize_public_key(msg.key)
|
|
||||||
if ID.from_pubkey(msg_pubkey) != msg.from_id:
|
|
||||||
logger.debug(
|
|
||||||
"Reject because signing key does not match sender ID for msg: %s",
|
|
||||||
msg,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
# Validate the signature of the message
|
# Validate the signature of the message
|
||||||
# First, construct the original payload that's signed by 'msg.key'
|
if not signature_validator(msg):
|
||||||
msg_without_key_sig = rpc_pb2.Message(
|
|
||||||
data=msg.data,
|
|
||||||
topicIDs=msg.topicIDs,
|
|
||||||
from_id=msg.from_id,
|
|
||||||
seqno=msg.seqno,
|
|
||||||
)
|
|
||||||
payload = (
|
|
||||||
PUBSUB_SIGNING_PREFIX.encode() + msg_without_key_sig.SerializeToString()
|
|
||||||
)
|
|
||||||
if not signature_validator(msg_pubkey, payload, msg.signature):
|
|
||||||
logger.debug("Signature validation failed for msg: %s", msg)
|
logger.debug("Signature validation failed for msg: %s", msg)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,41 @@
|
||||||
from libp2p.crypto.keys import PublicKey
|
import logging
|
||||||
|
|
||||||
|
from libp2p.crypto.serialization import deserialize_public_key
|
||||||
|
from libp2p.peer.id import ID
|
||||||
|
|
||||||
|
from .pb import rpc_pb2
|
||||||
|
|
||||||
|
logger = logging.getLogger("libp2p.pubsub")
|
||||||
|
|
||||||
|
PUBSUB_SIGNING_PREFIX = "libp2p-pubsub:"
|
||||||
|
|
||||||
|
|
||||||
def signature_validator(pubkey: PublicKey, payload: bytes, signature: bytes) -> bool:
|
def signature_validator(msg: rpc_pb2.Message) -> bool:
|
||||||
"""
|
"""
|
||||||
Verify the message against the given public key.
|
Verify the message against the given public key.
|
||||||
|
|
||||||
:param pubkey: the public key which signs the message.
|
:param pubkey: the public key which signs the message.
|
||||||
:param msg: the message signed.
|
:param msg: the message signed.
|
||||||
"""
|
"""
|
||||||
|
# Check if signature is attached
|
||||||
|
if msg.signature == b"":
|
||||||
|
logger.debug("Reject because no signature attached for msg: %s", msg)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Validate if message sender matches message signer,
|
||||||
|
# i.e., check if `msg.key` matches `msg.from_id`
|
||||||
|
msg_pubkey = deserialize_public_key(msg.key)
|
||||||
|
if ID.from_pubkey(msg_pubkey) != msg.from_id:
|
||||||
|
logger.debug(
|
||||||
|
"Reject because signing key does not match sender ID for msg: %s", msg
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
# First, construct the original payload that's signed by 'msg.key'
|
||||||
|
msg_without_key_sig = rpc_pb2.Message(
|
||||||
|
data=msg.data, topicIDs=msg.topicIDs, from_id=msg.from_id, seqno=msg.seqno
|
||||||
|
)
|
||||||
|
payload = PUBSUB_SIGNING_PREFIX.encode() + msg_without_key_sig.SerializeToString()
|
||||||
try:
|
try:
|
||||||
return pubkey.verify(payload, signature)
|
return msg_pubkey.verify(payload, msg.signature)
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
Loading…
Reference in New Issue
Block a user