github.com/decred/dcrlnd@v0.7.6/brontide/conn.go (about)

     1  package brontide
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"math"
     7  	"net"
     8  	"time"
     9  
    10  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    11  	"github.com/decred/dcrlnd/keychain"
    12  	"github.com/decred/dcrlnd/lnwire"
    13  	"github.com/decred/dcrlnd/tor"
    14  )
    15  
    16  // Conn is an implementation of net.Conn which enforces an authenticated key
    17  // exchange and message encryption protocol dubbed "Brontide" after initial TCP
    18  // connection establishment. In the case of a successful handshake, all
    19  // messages sent via the .Write() method are encrypted with an AEAD cipher
    20  // along with an encrypted length-prefix. See the Machine struct for
    21  // additional details w.r.t to the handshake and encryption scheme.
    22  type Conn struct {
    23  	conn net.Conn
    24  
    25  	noise *Machine
    26  
    27  	readBuf bytes.Buffer
    28  }
    29  
    30  // A compile-time assertion to ensure that Conn meets the net.Conn interface.
    31  var _ net.Conn = (*Conn)(nil)
    32  
    33  // Dial attempts to establish an encrypted+authenticated connection with the
    34  // remote peer located at address which has remotePub as its long-term static
    35  // public key. In the case of a handshake failure, the connection is closed and
    36  // a non-nil error is returned.
    37  func Dial(local keychain.SingleKeyECDH, netAddr *lnwire.NetAddress,
    38  	timeout time.Duration, dialer tor.DialFunc) (*Conn, error) {
    39  
    40  	ipAddr := netAddr.Address.String()
    41  	var conn net.Conn
    42  	var err error
    43  	conn, err = dialer("tcp", ipAddr, timeout)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	b := &Conn{
    49  		conn:  conn,
    50  		noise: NewBrontideMachine(true, local, netAddr.IdentityKey),
    51  	}
    52  
    53  	// Initiate the handshake by sending the first act to the receiver.
    54  	actOne, err := b.noise.GenActOne()
    55  	if err != nil {
    56  		b.conn.Close()
    57  		return nil, err
    58  	}
    59  	if _, err := conn.Write(actOne[:]); err != nil {
    60  		b.conn.Close()
    61  		return nil, err
    62  	}
    63  
    64  	// We'll ensure that we get ActTwo from the remote peer in a timely
    65  	// manner. If they don't respond within handshakeReadTimeout, then
    66  	// we'll kill the connection.
    67  	err = conn.SetReadDeadline(time.Now().Add(handshakeReadTimeout))
    68  	if err != nil {
    69  		b.conn.Close()
    70  		return nil, err
    71  	}
    72  
    73  	// If the first act was successful (we know that address is actually
    74  	// remotePub), then read the second act after which we'll be able to
    75  	// send our static public key to the remote peer with strong forward
    76  	// secrecy.
    77  	var actTwo [ActTwoSize]byte
    78  	if _, err := io.ReadFull(conn, actTwo[:]); err != nil {
    79  		b.conn.Close()
    80  		return nil, err
    81  	}
    82  	if err := b.noise.RecvActTwo(actTwo); err != nil {
    83  		b.conn.Close()
    84  		return nil, err
    85  	}
    86  
    87  	// Finally, complete the handshake by sending over our encrypted static
    88  	// key and execute the final ECDH operation.
    89  	actThree, err := b.noise.GenActThree()
    90  	if err != nil {
    91  		b.conn.Close()
    92  		return nil, err
    93  	}
    94  	if _, err := conn.Write(actThree[:]); err != nil {
    95  		b.conn.Close()
    96  		return nil, err
    97  	}
    98  
    99  	// We'll reset the deadline as it's no longer critical beyond the
   100  	// initial handshake.
   101  	err = conn.SetReadDeadline(time.Time{})
   102  	if err != nil {
   103  		b.conn.Close()
   104  		return nil, err
   105  	}
   106  
   107  	return b, nil
   108  }
   109  
   110  // ReadNextMessage uses the connection in a message-oriented manner, instructing
   111  // it to read the next _full_ message with the brontide stream. This function
   112  // will block until the read of the header and body succeeds.
   113  //
   114  // NOTE: This method SHOULD NOT be used in the case that the connection may be
   115  // adversarial and induce long delays. If the caller needs to set read deadlines
   116  // appropriately, it is preferred that they use the split ReadNextHeader and
   117  // ReadNextBody methods so that the deadlines can be set appropriately on each.
   118  func (c *Conn) ReadNextMessage() ([]byte, error) {
   119  	return c.noise.ReadMessage(c.conn)
   120  }
   121  
   122  // ReadNextHeader uses the connection to read the next header from the brontide
   123  // stream. This function will block until the read of the header succeeds and
   124  // return the packet length (including MAC overhead) that is expected from the
   125  // subsequent call to ReadNextBody.
   126  func (c *Conn) ReadNextHeader() (uint32, error) {
   127  	return c.noise.ReadHeader(c.conn)
   128  }
   129  
   130  // ReadNextBody uses the connection to read the next message body from the
   131  // brontide stream. This function will block until the read of the body succeeds
   132  // and return the decrypted payload. The provided buffer MUST be the packet
   133  // length returned by the preceding call to ReadNextHeader.
   134  func (c *Conn) ReadNextBody(buf []byte) ([]byte, error) {
   135  	return c.noise.ReadBody(c.conn, buf)
   136  }
   137  
   138  // Read reads data from the connection.  Read can be made to time out and
   139  // return an Error with Timeout() == true after a fixed time limit; see
   140  // SetDeadline and SetReadDeadline.
   141  //
   142  // Part of the net.Conn interface.
   143  func (c *Conn) Read(b []byte) (n int, err error) {
   144  	// In order to reconcile the differences between the record abstraction
   145  	// of our AEAD connection, and the stream abstraction of TCP, we
   146  	// maintain an intermediate read buffer. If this buffer becomes
   147  	// depleted, then we read the next record, and feed it into the
   148  	// buffer. Otherwise, we read directly from the buffer.
   149  	if c.readBuf.Len() == 0 {
   150  		plaintext, err := c.noise.ReadMessage(c.conn)
   151  		if err != nil {
   152  			return 0, err
   153  		}
   154  
   155  		if _, err := c.readBuf.Write(plaintext); err != nil {
   156  			return 0, err
   157  		}
   158  	}
   159  
   160  	return c.readBuf.Read(b)
   161  }
   162  
   163  // Write writes data to the connection.  Write can be made to time out and
   164  // return an Error with Timeout() == true after a fixed time limit; see
   165  // SetDeadline and SetWriteDeadline.
   166  //
   167  // Part of the net.Conn interface.
   168  func (c *Conn) Write(b []byte) (n int, err error) {
   169  	// If the message doesn't require any chunking, then we can go ahead
   170  	// with a single write.
   171  	if len(b) <= math.MaxUint16 {
   172  		err = c.noise.WriteMessage(b)
   173  		if err != nil {
   174  			return 0, err
   175  		}
   176  		return c.noise.Flush(c.conn)
   177  	}
   178  
   179  	// If we need to split the message into fragments, then we'll write
   180  	// chunks which maximize usage of the available payload.
   181  	chunkSize := math.MaxUint16
   182  
   183  	bytesToWrite := len(b)
   184  	bytesWritten := 0
   185  	for bytesWritten < bytesToWrite {
   186  		// If we're on the last chunk, then truncate the chunk size as
   187  		// necessary to avoid an out-of-bounds array memory access.
   188  		if bytesWritten+chunkSize > len(b) {
   189  			chunkSize = len(b) - bytesWritten
   190  		}
   191  
   192  		// Slice off the next chunk to be written based on our running
   193  		// counter and next chunk size.
   194  		chunk := b[bytesWritten : bytesWritten+chunkSize]
   195  		if err := c.noise.WriteMessage(chunk); err != nil {
   196  			return bytesWritten, err
   197  		}
   198  
   199  		n, err := c.noise.Flush(c.conn)
   200  		bytesWritten += n
   201  		if err != nil {
   202  			return bytesWritten, err
   203  		}
   204  	}
   205  
   206  	return bytesWritten, nil
   207  }
   208  
   209  // WriteMessage encrypts and buffers the next message p for the connection. The
   210  // ciphertext of the message is prepended with an encrypt+auth'd length which
   211  // must be used as the AD to the AEAD construction when being decrypted by the
   212  // other side.
   213  //
   214  // NOTE: This DOES NOT write the message to the wire, it should be followed by a
   215  // call to Flush to ensure the message is written.
   216  func (c *Conn) WriteMessage(b []byte) error {
   217  	return c.noise.WriteMessage(b)
   218  }
   219  
   220  // Flush attempts to write a message buffered using WriteMessage to the
   221  // underlying connection. If no buffered message exists, this will result in a
   222  // NOP. Otherwise, it will continue to write the remaining bytes, picking up
   223  // where the byte stream left off in the event of a partial write. The number of
   224  // bytes returned reflects the number of plaintext bytes in the payload, and
   225  // does not account for the overhead of the header or MACs.
   226  //
   227  // NOTE: It is safe to call this method again iff a timeout error is returned.
   228  func (c *Conn) Flush() (int, error) {
   229  	return c.noise.Flush(c.conn)
   230  }
   231  
   232  // Close closes the connection. Any blocked Read or Write operations will be
   233  // unblocked and return errors.
   234  //
   235  // Part of the net.Conn interface.
   236  func (c *Conn) Close() error {
   237  	// TODO(roasbeef): reset brontide state?
   238  	return c.conn.Close()
   239  }
   240  
   241  // LocalAddr returns the local network address.
   242  //
   243  // Part of the net.Conn interface.
   244  func (c *Conn) LocalAddr() net.Addr {
   245  	return c.conn.LocalAddr()
   246  }
   247  
   248  // RemoteAddr returns the remote network address.
   249  //
   250  // Part of the net.Conn interface.
   251  func (c *Conn) RemoteAddr() net.Addr {
   252  	return c.conn.RemoteAddr()
   253  }
   254  
   255  // SetDeadline sets the read and write deadlines associated with the
   256  // connection. It is equivalent to calling both SetReadDeadline and
   257  // SetWriteDeadline.
   258  //
   259  // Part of the net.Conn interface.
   260  func (c *Conn) SetDeadline(t time.Time) error {
   261  	return c.conn.SetDeadline(t)
   262  }
   263  
   264  // SetReadDeadline sets the deadline for future Read calls. A zero value for t
   265  // means Read will not time out.
   266  //
   267  // Part of the net.Conn interface.
   268  func (c *Conn) SetReadDeadline(t time.Time) error {
   269  	return c.conn.SetReadDeadline(t)
   270  }
   271  
   272  // SetWriteDeadline sets the deadline for future Write calls. Even if write
   273  // times out, it may return n > 0, indicating that some of the data was
   274  // successfully written. A zero value for t means Write will not time out.
   275  //
   276  // Part of the net.Conn interface.
   277  func (c *Conn) SetWriteDeadline(t time.Time) error {
   278  	return c.conn.SetWriteDeadline(t)
   279  }
   280  
   281  // RemotePub returns the remote peer's static public key.
   282  func (c *Conn) RemotePub() *secp256k1.PublicKey {
   283  	return c.noise.remoteStatic
   284  }
   285  
   286  // LocalPub returns the local peer's static public key.
   287  func (c *Conn) LocalPub() *secp256k1.PublicKey {
   288  	return c.noise.localStatic.PubKey()
   289  }