| // TLS low level connection and record layer | |
| package tls | |
| import ( | |
| "bytes" | |
| "crypto/subtle" | |
| "hash" | |
| "io" | |
| "net" | |
| "os" | |
| "sync" | |
| ) | |
| // A Conn represents a secured connection. | |
| // It implements the net.Conn interface. | |
| type Conn struct { | |
| // constant | |
| conn net.Conn | |
| isClient bool | |
| // constant after handshake; protected by handshakeMutex | |
| handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex | |
| vers uint16 // TLS version | |
| haveVers bool // version has been negotiated | |
| config *Config // configuration passed to constructor | |
| handshakeComplete bool | |
| cipherSuite uint16 | |
| clientProtocol string | |
| // first permanent error | |
| errMutex sync.Mutex | |
| err os.Error | |
| // input/output | |
| in, out halfConn // in.Mutex < out.Mutex | |
| rawInput *block // raw input, right off the wire | |
| input *block // application data waiting to be read | |
| hand bytes.Buffer // handshake data waiting to be read | |
| tmp [16]byte | |
| } | |
| func (c *Conn) setError(err os.Error) os.Error { | |
| c.errMutex.Lock() | |
| defer c.errMutex.Unlock() | |
| if c.err == nil { | |
| c.err = err | |
| } | |
| return err | |
| } | |
| func (c *Conn) error() os.Error { | |
| c.errMutex.Lock() | |
| defer c.errMutex.Unlock() | |
| return c.err | |
| } | |
| // Access to net.Conn methods. | |
| // Cannot just embed net.Conn because that would | |
| // export the struct field too. | |
| // LocalAddr returns the local network address. | |
| func (c *Conn) LocalAddr() net.Addr { | |
| return c.conn.LocalAddr() | |
| } | |
| // RemoteAddr returns the remote network address. | |
| func (c *Conn) RemoteAddr() net.Addr { | |
| return c.conn.RemoteAddr() | |
| } | |
| // SetTimeout sets the read deadline associated with the connection. | |
| // There is no write deadline. | |
| func (c *Conn) SetTimeout(nsec int64) os.Error { | |
| return c.conn.SetTimeout(nsec) | |
| } | |
| // SetReadTimeout sets the time (in nanoseconds) that | |
| // Read will wait for data before returning os.EAGAIN. | |
| // Setting nsec == 0 (the default) disables the deadline. | |
| func (c *Conn) SetReadTimeout(nsec int64) os.Error { | |
| return c.conn.SetReadTimeout(nsec) | |
| } | |
| // SetWriteTimeout exists to satisfy the net.Conn interface | |
| // but is not implemented by TLS. It always returns an error. | |
| func (c *Conn) SetWriteTimeout(nsec int64) os.Error { | |
| return os.NewError("TLS does not support SetWriteTimeout") | |
| } | |
| // A halfConn represents one direction of the record layer | |
| // connection, either sending or receiving. | |
| type halfConn struct { | |
| sync.Mutex | |
| crypt encryptor // encryption state | |
| mac hash.Hash // MAC algorithm | |
| seq [8]byte // 64-bit sequence number | |
| bfree *block // list of free blocks | |
| nextCrypt encryptor // next encryption state | |
| nextMac hash.Hash // next MAC algorithm | |
| } | |
| // prepareCipherSpec sets the encryption and MAC states | |
| // that a subsequent changeCipherSpec will use. | |
| func (hc *halfConn) prepareCipherSpec(crypt encryptor, mac hash.Hash) { | |
| hc.nextCrypt = crypt | |
| hc.nextMac = mac | |
| } | |
| // changeCipherSpec changes the encryption and MAC states | |
| // to the ones previously passed to prepareCipherSpec. | |
| func (hc *halfConn) changeCipherSpec() os.Error { | |
| if hc.nextCrypt == nil { | |
| return alertInternalError | |
| } | |
| hc.crypt = hc.nextCrypt | |
| hc.mac = hc.nextMac | |
| hc.nextCrypt = nil | |
| hc.nextMac = nil | |
| return nil | |
| } | |
| // incSeq increments the sequence number. | |
| func (hc *halfConn) incSeq() { | |
| for i := 7; i >= 0; i-- { | |
| hc.seq[i]++ | |
| if hc.seq[i] != 0 { | |
| return | |
| } | |
| } | |
| // Not allowed to let sequence number wrap. | |
| // Instead, must renegotiate before it does. | |
| // Not likely enough to bother. | |
| panic("TLS: sequence number wraparound") | |
| } | |
| // resetSeq resets the sequence number to zero. | |
| func (hc *halfConn) resetSeq() { | |
| for i := range hc.seq { | |
| hc.seq[i] = 0 | |
| } | |
| } | |
| // decrypt checks and strips the mac and decrypts the data in b. | |
| func (hc *halfConn) decrypt(b *block) (bool, alert) { | |
| // pull out payload | |
| payload := b.data[recordHeaderLen:] | |
| // decrypt | |
| if hc.crypt != nil { | |
| hc.crypt.XORKeyStream(payload) | |
| } | |
| // check, strip mac | |
| if hc.mac != nil { | |
| if len(payload) < hc.mac.Size() { | |
| return false, alertBadRecordMAC | |
| } | |
| // strip mac off payload, b.data | |
| n := len(payload) - hc.mac.Size() | |
| b.data[3] = byte(n >> 8) | |
| b.data[4] = byte(n) | |
| b.data = b.data[0 : recordHeaderLen+n] | |
| remoteMAC := payload[n:] | |
| hc.mac.Reset() | |
| hc.mac.Write(hc.seq[0:]) | |
| hc.incSeq() | |
| hc.mac.Write(b.data) | |
| if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 { | |
| return false, alertBadRecordMAC | |
| } | |
| } | |
| return true, 0 | |
| } | |
| // encrypt encrypts and macs the data in b. | |
| func (hc *halfConn) encrypt(b *block) (bool, alert) { | |
| // mac | |
| if hc.mac != nil { | |
| hc.mac.Reset() | |
| hc.mac.Write(hc.seq[0:]) | |
| hc.incSeq() | |
| hc.mac.Write(b.data) | |
| mac := hc.mac.Sum() | |
| n := len(b.data) | |
| b.resize(n + len(mac)) | |
| copy(b.data[n:], mac) | |
| // update length to include mac | |
| n = len(b.data) - recordHeaderLen | |
| b.data[3] = byte(n >> 8) | |
| b.data[4] = byte(n) | |
| } | |
| // encrypt | |
| if hc.crypt != nil { | |
| hc.crypt.XORKeyStream(b.data[recordHeaderLen:]) | |
| } | |
| return true, 0 | |
| } | |
| // A block is a simple data buffer. | |
| type block struct { | |
| data []byte | |
| off int // index for Read | |
| link *block | |
| } | |
| // resize resizes block to be n bytes, growing if necessary. | |
| func (b *block) resize(n int) { | |
| if n > cap(b.data) { | |
| b.reserve(n) | |
| } | |
| b.data = b.data[0:n] | |
| } | |
| // reserve makes sure that block contains a capacity of at least n bytes. | |
| func (b *block) reserve(n int) { | |
| if cap(b.data) >= n { | |
| return | |
| } | |
| m := cap(b.data) | |
| if m == 0 { | |
| m = 1024 | |
| } | |
| for m < n { | |
| m *= 2 | |
| } | |
| data := make([]byte, len(b.data), m) | |
| copy(data, b.data) | |
| b.data = data | |
| } | |
| // readFromUntil reads from r into b until b contains at least n bytes | |
| // or else returns an error. | |
| func (b *block) readFromUntil(r io.Reader, n int) os.Error { | |
| // quick case | |
| if len(b.data) >= n { | |
| return nil | |
| } | |
| // read until have enough. | |
| b.reserve(n) | |
| for { | |
| m, err := r.Read(b.data[len(b.data):cap(b.data)]) | |
| b.data = b.data[0 : len(b.data)+m] | |
| if len(b.data) >= n { | |
| break | |
| } | |
| if err != nil { | |
| return err | |
| } | |
| } | |
| return nil | |
| } | |
| func (b *block) Read(p []byte) (n int, err os.Error) { | |
| n = copy(p, b.data[b.off:]) | |
| b.off += n | |
| return | |
| } | |
| // newBlock allocates a new block, from hc's free list if possible. | |
| func (hc *halfConn) newBlock() *block { | |
| b := hc.bfree | |
| if b == nil { | |
| return new(block) | |
| } | |
| hc.bfree = b.link | |
| b.link = nil | |
| b.resize(0) | |
| return b | |
| } | |
| // freeBlock returns a block to hc's free list. | |
| // The protocol is such that each side only has a block or two on | |
| // its free list at a time, so there's no need to worry about | |
| // trimming the list, etc. | |
| func (hc *halfConn) freeBlock(b *block) { | |
| b.link = hc.bfree | |
| hc.bfree = b | |
| } | |
| // splitBlock splits a block after the first n bytes, | |
| // returning a block with those n bytes and a | |
| // block with the remaindec. the latter may be nil. | |
| func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) { | |
| if len(b.data) <= n { | |
| return b, nil | |
| } | |
| bb := hc.newBlock() | |
| bb.resize(len(b.data) - n) | |
| copy(bb.data, b.data[n:]) | |
| b.data = b.data[0:n] | |
| return b, bb | |
| } | |
| // readRecord reads the next TLS record from the connection | |
| // and updates the record layer state. | |
| // c.in.Mutex <= L; c.input == nil. | |
| func (c *Conn) readRecord(want recordType) os.Error { | |
| // Caller must be in sync with connection: | |
| // handshake data if handshake not yet completed, | |
| // else application data. (We don't support renegotiation.) | |
| switch want { | |
| default: | |
| return c.sendAlert(alertInternalError) | |
| case recordTypeHandshake, recordTypeChangeCipherSpec: | |
| if c.handshakeComplete { | |
| return c.sendAlert(alertInternalError) | |
| } | |
| case recordTypeApplicationData: | |
| if !c.handshakeComplete { | |
| return c.sendAlert(alertInternalError) | |
| } | |
| } | |
| Again: | |
| if c.rawInput == nil { | |
| c.rawInput = c.in.newBlock() | |
| } | |
| b := c.rawInput | |
| // Read header, payload. | |
| if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil { | |
| // RFC suggests that EOF without an alertCloseNotify is | |
| // an error, but popular web sites seem to do this, | |
| // so we can't make it an error. | |
| // if err == os.EOF { | |
| // err = io.ErrUnexpectedEOF | |
| // } | |
| if e, ok := err.(net.Error); !ok || !e.Temporary() { | |
| c.setError(err) | |
| } | |
| return err | |
| } | |
| typ := recordType(b.data[0]) | |
| vers := uint16(b.data[1])<<8 | uint16(b.data[2]) | |
| n := int(b.data[3])<<8 | int(b.data[4]) | |
| if c.haveVers && vers != c.vers { | |
| return c.sendAlert(alertProtocolVersion) | |
| } | |
| if n > maxCiphertext { | |
| return c.sendAlert(alertRecordOverflow) | |
| } | |
| if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil { | |
| if err == os.EOF { | |
| err = io.ErrUnexpectedEOF | |
| } | |
| if e, ok := err.(net.Error); !ok || !e.Temporary() { | |
| c.setError(err) | |
| } | |
| return err | |
| } | |
| // Process message. | |
| b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n) | |
| b.off = recordHeaderLen | |
| if ok, err := c.in.decrypt(b); !ok { | |
| return c.sendAlert(err) | |
| } | |
| data := b.data[b.off:] | |
| if len(data) > maxPlaintext { | |
| c.sendAlert(alertRecordOverflow) | |
| c.in.freeBlock(b) | |
| return c.error() | |
| } | |
| switch typ { | |
| default: | |
| c.sendAlert(alertUnexpectedMessage) | |
| case recordTypeAlert: | |
| if len(data) != 2 { | |
| c.sendAlert(alertUnexpectedMessage) | |
| break | |
| } | |
| if alert(data[1]) == alertCloseNotify { | |
| c.setError(os.EOF) | |
| break | |
| } | |
| switch data[0] { | |
| case alertLevelWarning: | |
| // drop on the floor | |
| c.in.freeBlock(b) | |
| goto Again | |
| case alertLevelError: | |
| c.setError(&net.OpError{Op: "remote error", Error: alert(data[1])}) | |
| default: | |
| c.sendAlert(alertUnexpectedMessage) | |
| } | |
| case recordTypeChangeCipherSpec: | |
| if typ != want || len(data) != 1 || data[0] != 1 { | |
| c.sendAlert(alertUnexpectedMessage) | |
| break | |
| } | |
| err := c.in.changeCipherSpec() | |
| if err != nil { | |
| c.sendAlert(err.(alert)) | |
| } | |
| case recordTypeApplicationData: | |
| if typ != want { | |
| c.sendAlert(alertUnexpectedMessage) | |
| break | |
| } | |
| c.input = b | |
| b = nil | |
| case recordTypeHandshake: | |
| // TODO(rsc): Should at least pick off connection close. | |
| if typ != want { | |
| return c.sendAlert(alertNoRenegotiation) | |
| } | |
| c.hand.Write(data) | |
| } | |
| if b != nil { | |
| c.in.freeBlock(b) | |
| } | |
| return c.error() | |
| } | |
| // sendAlert sends a TLS alert message. | |
| // c.out.Mutex <= L. | |
| func (c *Conn) sendAlertLocked(err alert) os.Error { | |
| c.tmp[0] = alertLevelError | |
| if err == alertNoRenegotiation { | |
| c.tmp[0] = alertLevelWarning | |
| } | |
| c.tmp[1] = byte(err) | |
| c.writeRecord(recordTypeAlert, c.tmp[0:2]) | |
| return c.setError(&net.OpError{Op: "local error", Error: err}) | |
| } | |
| // sendAlert sends a TLS alert message. | |
| // L < c.out.Mutex. | |
| func (c *Conn) sendAlert(err alert) os.Error { | |
| c.out.Lock() | |
| defer c.out.Unlock() | |
| return c.sendAlertLocked(err) | |
| } | |
| // writeRecord writes a TLS record with the given type and payload | |
| // to the connection and updates the record layer state. | |
| // c.out.Mutex <= L. | |
| func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err os.Error) { | |
| b := c.out.newBlock() | |
| for len(data) > 0 { | |
| m := len(data) | |
| if m > maxPlaintext { | |
| m = maxPlaintext | |
| } | |
| b.resize(recordHeaderLen + m) | |
| b.data[0] = byte(typ) | |
| vers := c.vers | |
| if vers == 0 { | |
| vers = maxVersion | |
| } | |
| b.data[1] = byte(vers >> 8) | |
| b.data[2] = byte(vers) | |
| b.data[3] = byte(m >> 8) | |
| b.data[4] = byte(m) | |
| copy(b.data[recordHeaderLen:], data) | |
| c.out.encrypt(b) | |
| _, err = c.conn.Write(b.data) | |
| if err != nil { | |
| break | |
| } | |
| n += m | |
| data = data[m:] | |
| } | |
| c.out.freeBlock(b) | |
| if typ == recordTypeChangeCipherSpec { | |
| err = c.out.changeCipherSpec() | |
| if err != nil { | |
| // Cannot call sendAlert directly, | |
| // because we already hold c.out.Mutex. | |
| c.tmp[0] = alertLevelError | |
| c.tmp[1] = byte(err.(alert)) | |
| c.writeRecord(recordTypeAlert, c.tmp[0:2]) | |
| c.err = &net.OpError{Op: "local error", Error: err} | |
| return n, c.err | |
| } | |
| } | |
| return | |
| } | |
| // readHandshake reads the next handshake message from | |
| // the record layer. | |
| // c.in.Mutex < L; c.out.Mutex < L. | |
| func (c *Conn) readHandshake() (interface{}, os.Error) { | |
| for c.hand.Len() < 4 { | |
| if c.err != nil { | |
| return nil, c.err | |
| } | |
| c.readRecord(recordTypeHandshake) | |
| } | |
| data := c.hand.Bytes() | |
| n := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) | |
| if n > maxHandshake { | |
| c.sendAlert(alertInternalError) | |
| return nil, c.err | |
| } | |
| for c.hand.Len() < 4+n { | |
| if c.err != nil { | |
| return nil, c.err | |
| } | |
| c.readRecord(recordTypeHandshake) | |
| } | |
| data = c.hand.Next(4 + n) | |
| var m handshakeMessage | |
| switch data[0] { | |
| case typeClientHello: | |
| m = new(clientHelloMsg) | |
| case typeServerHello: | |
| m = new(serverHelloMsg) | |
| case typeCertificate: | |
| m = new(certificateMsg) | |
| case typeServerHelloDone: | |
| m = new(serverHelloDoneMsg) | |
| case typeClientKeyExchange: | |
| m = new(clientKeyExchangeMsg) | |
| case typeNextProtocol: | |
| m = new(nextProtoMsg) | |
| case typeFinished: | |
| m = new(finishedMsg) | |
| default: | |
| c.sendAlert(alertUnexpectedMessage) | |
| return nil, alertUnexpectedMessage | |
| } | |
| // The handshake message unmarshallers | |
| // expect to be able to keep references to data, | |
| // so pass in a fresh copy that won't be overwritten. | |
| data = bytes.Add(nil, data) | |
| if !m.unmarshal(data) { | |
| c.sendAlert(alertUnexpectedMessage) | |
| return nil, alertUnexpectedMessage | |
| } | |
| return m, nil | |
| } | |
| // Write writes data to the connection. | |
| func (c *Conn) Write(b []byte) (n int, err os.Error) { | |
| if err = c.Handshake(); err != nil { | |
| return | |
| } | |
| c.out.Lock() | |
| defer c.out.Unlock() | |
| if !c.handshakeComplete { | |
| return 0, alertInternalError | |
| } | |
| if c.err != nil { | |
| return 0, c.err | |
| } | |
| return c.writeRecord(recordTypeApplicationData, b) | |
| } | |
| // Read can be made to time out and return err == os.EAGAIN | |
| // after a fixed time limit; see SetTimeout and SetReadTimeout. | |
| func (c *Conn) Read(b []byte) (n int, err os.Error) { | |
| if err = c.Handshake(); err != nil { | |
| return | |
| } | |
| c.in.Lock() | |
| defer c.in.Unlock() | |
| for c.input == nil && c.err == nil { | |
| c.readRecord(recordTypeApplicationData) | |
| } | |
| if c.err != nil { | |
| return 0, c.err | |
| } | |
| n, err = c.input.Read(b) | |
| if c.input.off >= len(c.input.data) { | |
| c.in.freeBlock(c.input) | |
| c.input = nil | |
| } | |
| return n, nil | |
| } | |
| // Close closes the connection. | |
| func (c *Conn) Close() os.Error { | |
| if err := c.Handshake(); err != nil { | |
| return err | |
| } | |
| return c.sendAlert(alertCloseNotify) | |
| } | |
| // Handshake runs the client or server handshake | |
| // protocol if it has not yet been run. | |
| // Most uses of this packge need not call Handshake | |
| // explicitly: the first Read or Write will call it automatically. | |
| func (c *Conn) Handshake() os.Error { | |
| c.handshakeMutex.Lock() | |
| defer c.handshakeMutex.Unlock() | |
| if err := c.error(); err != nil { | |
| return err | |
| } | |
| if c.handshakeComplete { | |
| return nil | |
| } | |
| if c.isClient { | |
| return c.clientHandshake() | |
| } | |
| return c.serverHandshake() | |
| } | |
| // If c is a TLS server, ClientConnection returns the protocol | |
| // requested by the client during the TLS handshake. | |
| // Handshake must have been called already. | |
| func (c *Conn) ClientConnection() string { | |
| c.handshakeMutex.Lock() | |
| defer c.handshakeMutex.Unlock() | |
| return c.clientProtocol | |
| } |