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 }