th5/conn.go
Adam Langley cbf5c897cb crypto/tls: add client-side SNI support and PeerCertificates.
SNI (Server Name Indication) is a way for a TLS client to
indicate to the server which name it knows the server by. This
allows the server to have several names and return the correct
certificate for each (virtual hosting).

PeerCertificates returns the list of certificates presented by
server.

R=r
CC=golang-dev
https://golang.org/cl/1741053
2010-07-21 11:36:01 -04:00

665 lines
15 KiB
Go

// TLS low level connection and record layer
package tls
import (
"bytes"
"crypto/subtle"
"crypto/x509"
"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
ocspResponse []byte // stapled OCSP response
peerCertificates []*x509.Certificate
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 typeCertificateStatus:
m = new(certificateStatusMsg)
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()
}
// ConnectionState returns basic TLS details about the connection.
func (c *Conn) ConnectionState() ConnectionState {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
var state ConnectionState
state.HandshakeComplete = c.handshakeComplete
if c.handshakeComplete {
state.NegotiatedProtocol = c.clientProtocol
state.CipherSuite = c.cipherSuite
}
return state
}
// OCSPResponse returns the stapled OCSP response from the TLS server, if
// any. (Only valid for client connections.)
func (c *Conn) OCSPResponse() []byte {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
return c.ocspResponse
}
// PeerCertificates returns the certificate chain that was presented by the
// other side.
func (c *Conn) PeerCertificates() []*x509.Certificate {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
return c.peerCertificates
}