[wip] sketch of secio handshake

This commit is contained in:
Alex Stokes 2019-08-16 18:54:06 -07:00
parent fd08bcf624
commit 26165b0729
No known key found for this signature in database
GPG Key ID: 51CE1721B245C086

View File

@ -0,0 +1,137 @@
from dataclasses import dataclass
from typing import Optional
from libp2p.crypto.keys import PrivateKey
from libp2p.network.connection.raw_connection_interface import IRawConnection
from libp2p.peer.id import ID as PeerID
from libp2p.security.base_session import BaseSession
from libp2p.security.base_transport import BaseSecureTransport
from libp2p.security.secure_conn_interface import ISecureConn
ID = "/secio/1.0.0"
@dataclass
class NegotiationContext(frozen=True):
local_peer: PeerID
remote_peer: Optional[PeerID]
local_private_key: PrivateKey
conn: IRawConnection
class SecureSession(BaseSession):
pass
def _mk_serialized_proposal(negotiation_context: NegotiationContext) -> bytes:
pass
async def _response_to_msg(msg) -> bytes:
return bytes()
async def _establish_session_parameters():
# propose parameters
local_proposal = _mk_local_proposal(negotiation_context)
serialized_local_proposal = _mk_serialized_proposal(local_proposal)
serialized_remote_proposal = await _response_to_msg(serialized_local_proposal)
remote_proposal = _parse_proposal(serialized_remote_proposal)
# identify peer
remote_peer = _peer_from_proposal(remote_proposal)
# select enc params
encryption_parameters = _select_encryption_parameters(remote_proposal)
# exchange ephemeral pub keys
local_ephemeral_key_pair, shared_key_generator = create_elliptic_key_pair(
encryption_parameters
)
local_selection = _mk_serialized_selection(
local_proposal, remote_proposal, local_ephemeral_key_pair.public_key
)
serialized_local_selection = _mk_serialized_selection(local_selection)
local_exchange = _mk_exchange(
local_ephemeral_key_pair.public_key, serialized_local_selection
)
serialized_local_exchange = _mk_serialized_exchange_msg(local_exchange)
serialized_remote_exchange = await _response_to_msg(serialized_local_exchange)
remote_exchange = _parse_exchange(serialized_remote_exchange)
remote_selection = _mk_remote_selection(
remote_exchange, local_proposal, remote_proposal
)
verify_exchange(remote_exchange, remote_selection, remote_proposal)
# return all the data we need
def _mk_session_from(session_parameters):
# use ephemeral pubkey to make a shared key
# stretch shared key to get two keys
# decide which side has which key
# set up mac and cipher, based on shared key, for each side
# make new rdr/wtr pairs using each mac/cipher gadget
pass
async def _close_handshake(session):
# send nonce over encrypted channel
# verify we get our nonce back
pass
async def _run_handshake(negotiation_context: NegotiationContext):
"""
Attempts the initial `secio` handshake with the remote peer.
Successfully completing this routine implies ``self``'s instance
of this session is now ready for secure communication.
"""
session_parameters = await _establish_session_parameters()
session = _mk_session_from(session_parameters)
await _close_handshake(session)
return session
async def create_secure_session(
transport: BaseSecureTransport, conn: IRawConnection, remote_peer: PeerID = None
) -> ISecureConn:
negotiation_context = NegotiationContext(
transport.local_peer, remote_peer, transport.local_private_key, conn
)
return await _run_handshake(negotiation_context)
class SecIOTransport(BaseSecureTransport):
"""
``SecIOTransport`` provides a security upgrader for a ``IRawConnection``,
following the `secio` protocol defined in the libp2p specs.
"""
async def secure_inbound(self, conn: IRawConnection) -> ISecureConn:
"""
Secure the connection, either locally or by communicating with opposing node via conn,
for an inbound connection (i.e. we are not the initiator)
:return: secure connection object (that implements secure_conn_interface)
"""
return await create_secure_session(self, conn)
async def secure_outbound(
self, conn: IRawConnection, peer_id: PeerID
) -> ISecureConn:
"""
Secure the connection, either locally or by communicating with opposing node via conn,
for an inbound connection (i.e. we are the initiator)
:return: secure connection object (that implements secure_conn_interface)
"""
return await create_secure_session(self, conn, peer_id)