URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [crypto/] [tls/] [conn.go] - Rev 747
Compare with Previous | Blame | View Log
// Copyright 2010 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// TLS low level connection and record layerpackage tlsimport ("bytes""crypto/cipher""crypto/subtle""crypto/x509""errors""io""net""sync""time")// A Conn represents a secured connection.// It implements the net.Conn interface.type Conn struct {// constantconn net.ConnisClient bool// constant after handshake; protected by handshakeMutexhandshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutexvers uint16 // TLS versionhaveVers bool // version has been negotiatedconfig *Config // configuration passed to constructorhandshakeComplete boolcipherSuite uint16ocspResponse []byte // stapled OCSP responsepeerCertificates []*x509.Certificate// verifiedChains contains the certificate chains that we built, as// opposed to the ones presented by the server.verifiedChains [][]*x509.Certificate// serverName contains the server name indicated by the client, if any.serverName stringclientProtocol stringclientProtocolFallback bool// first permanent errorerrMutex sync.Mutexerr error// input/outputin, out halfConn // in.Mutex < out.MutexrawInput *block // raw input, right off the wireinput *block // application data waiting to be readhand bytes.Buffer // handshake data waiting to be readtmp [16]byte}func (c *Conn) setError(err error) error {c.errMutex.Lock()defer c.errMutex.Unlock()if c.err == nil {c.err = err}return err}func (c *Conn) error() 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()}// SetDeadline sets the read deadline associated with the connection.// There is no write deadline.// A zero value for t means Read will not time out.func (c *Conn) SetDeadline(t time.Time) error {return c.conn.SetDeadline(t)}// SetReadDeadline sets the read deadline on the underlying connection.// A zero value for t means Read will not time out.func (c *Conn) SetReadDeadline(t time.Time) error {return c.conn.SetReadDeadline(t)}// SetWriteDeadline exists to satisfy the net.Conn interface// but is not implemented by TLS. It always returns an error.func (c *Conn) SetWriteDeadline(t time.Time) error {return errors.New("TLS does not support SetWriteDeadline")}// A halfConn represents one direction of the record layer// connection, either sending or receiving.type halfConn struct {sync.Mutexversion uint16 // protocol versioncipher interface{} // cipher algorithmmac macFunctionseq [8]byte // 64-bit sequence numberbfree *block // list of free blocksnextCipher interface{} // next encryption statenextMac macFunction // next MAC algorithm// used to save allocating a new buffer for each MAC.inDigestBuf, outDigestBuf []byte}// prepareCipherSpec sets the encryption and MAC states// that a subsequent changeCipherSpec will use.func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {hc.version = versionhc.nextCipher = cipherhc.nextMac = mac}// changeCipherSpec changes the encryption and MAC states// to the ones previously passed to prepareCipherSpec.func (hc *halfConn) changeCipherSpec() error {if hc.nextCipher == nil {return alertInternalError}hc.cipher = hc.nextCipherhc.mac = hc.nextMachc.nextCipher = nilhc.nextMac = nilreturn 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}}// removePadding returns an unpadded slice, in constant time, which is a prefix// of the input. It also returns a byte which is equal to 255 if the padding// was valid and 0 otherwise. See RFC 2246, section 6.2.3.2func removePadding(payload []byte) ([]byte, byte) {if len(payload) < 1 {return payload, 0}paddingLen := payload[len(payload)-1]t := uint(len(payload)-1) - uint(paddingLen)// if len(payload) >= (paddingLen - 1) then the MSB of t is zerogood := byte(int32(^t) >> 31)toCheck := 255 // the maximum possible padding length// The length of the padded data is public, so we can use an if hereif toCheck+1 > len(payload) {toCheck = len(payload) - 1}for i := 0; i < toCheck; i++ {t := uint(paddingLen) - uint(i)// if i <= paddingLen then the MSB of t is zeromask := byte(int32(^t) >> 31)b := payload[len(payload)-1-i]good &^= mask&paddingLen ^ mask&b}// We AND together the bits of good and replicate the result across// all the bits.good &= good << 4good &= good << 2good &= good << 1good = uint8(int8(good) >> 7)toRemove := good&paddingLen + 1return payload[:len(payload)-int(toRemove)], good}// removePaddingSSL30 is a replacement for removePadding in the case that the// protocol version is SSLv3. In this version, the contents of the padding// are random and cannot be checked.func removePaddingSSL30(payload []byte) ([]byte, byte) {if len(payload) < 1 {return payload, 0}paddingLen := int(payload[len(payload)-1]) + 1if paddingLen > len(payload) {return payload, 0}return payload[:len(payload)-paddingLen], 255}func roundUp(a, b int) int {return a + (b-a%b)%b}// decrypt checks and strips the mac and decrypts the data in b.func (hc *halfConn) decrypt(b *block) (bool, alert) {// pull out payloadpayload := b.data[recordHeaderLen:]macSize := 0if hc.mac != nil {macSize = hc.mac.Size()}paddingGood := byte(255)// decryptif hc.cipher != nil {switch c := hc.cipher.(type) {case cipher.Stream:c.XORKeyStream(payload, payload)case cipher.BlockMode:blockSize := c.BlockSize()if len(payload)%blockSize != 0 || len(payload) < roundUp(macSize+1, blockSize) {return false, alertBadRecordMAC}c.CryptBlocks(payload, payload)if hc.version == versionSSL30 {payload, paddingGood = removePaddingSSL30(payload)} else {payload, paddingGood = removePadding(payload)}b.resize(recordHeaderLen + len(payload))// note that we still have a timing side-channel in the// MAC check, below. An attacker can align the record// so that a correct padding will cause one less hash// block to be calculated. Then they can iteratively// decrypt a record by breaking each byte. See// "Password Interception in a SSL/TLS Channel", Brice// Canvel et al.//// However, our behavior matches OpenSSL, so we leak// only as much as they do.default:panic("unknown cipher type")}}// check, strip macif hc.mac != nil {if len(payload) < macSize {return false, alertBadRecordMAC}// strip mac off payload, b.datan := len(payload) - macSizeb.data[3] = byte(n >> 8)b.data[4] = byte(n)b.resize(recordHeaderLen + n)remoteMAC := payload[n:]localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data)hc.incSeq()if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 {return false, alertBadRecordMAC}hc.inDigestBuf = localMAC}return true, 0}// padToBlockSize calculates the needed padding block, if any, for a payload.// On exit, prefix aliases payload and extends to the end of the last full// block of payload. finalBlock is a fresh slice which contains the contents of// any suffix of payload as well as the needed padding to make finalBlock a// full block.func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) {overrun := len(payload) % blockSizepaddingLen := blockSize - overrunprefix = payload[:len(payload)-overrun]finalBlock = make([]byte, blockSize)copy(finalBlock, payload[len(payload)-overrun:])for i := overrun; i < blockSize; i++ {finalBlock[i] = byte(paddingLen - 1)}return}// encrypt encrypts and macs the data in b.func (hc *halfConn) encrypt(b *block) (bool, alert) {// macif hc.mac != nil {mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data)hc.incSeq()n := len(b.data)b.resize(n + len(mac))copy(b.data[n:], mac)hc.outDigestBuf = mac}payload := b.data[recordHeaderLen:]// encryptif hc.cipher != nil {switch c := hc.cipher.(type) {case cipher.Stream:c.XORKeyStream(payload, payload)case cipher.BlockMode:prefix, finalBlock := padToBlockSize(payload, c.BlockSize())b.resize(recordHeaderLen + len(prefix) + len(finalBlock))c.CryptBlocks(b.data[recordHeaderLen:], prefix)c.CryptBlocks(b.data[recordHeaderLen+len(prefix):], finalBlock)default:panic("unknown cipher type")}}// update length to include MAC and any block padding needed.n := len(b.data) - recordHeaderLenb.data[3] = byte(n >> 8)b.data[4] = byte(n)return true, 0}// A block is a simple data buffer.type block struct {data []byteoff int // index for Readlink *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) error {// quick caseif 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 error) {n = copy(p, b.data[b.off:])b.off += nreturn}// newBlock allocates a new block, from hc's free list if possible.func (hc *halfConn) newBlock() *block {b := hc.bfreeif b == nil {return new(block)}hc.bfree = b.linkb.link = nilb.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.bfreehc.bfree = b}// splitBlock splits a block after the first n bytes,// returning a block with those n bytes and a// block with the remainder. 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) 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 == io.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 !c.haveVers {// First message, be extra suspicious:// this might not be a TLS client.// Bail out before reading a full 'body', if possible.// The current max version is 3.1.// If the version is >= 16.0, it's probably not real.// Similarly, a clientHello message encodes in// well under a kilobyte. If the length is >= 12 kB,// it's probably not real.if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 {return c.sendAlert(alertUnexpectedMessage)}}if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {if err == io.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 = recordHeaderLenif 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(io.EOF)break}switch data[0] {case alertLevelWarning:// drop on the floorc.in.freeBlock(b)goto Againcase alertLevelError:c.setError(&net.OpError{Op: "remote error", Err: 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 = bb = nilcase 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) error {c.tmp[0] = alertLevelErrorif err == alertNoRenegotiation {c.tmp[0] = alertLevelWarning}c.tmp[1] = byte(err)c.writeRecord(recordTypeAlert, c.tmp[0:2])// closeNotify is a special case in that it isn't an error:if err != alertCloseNotify {return c.setError(&net.OpError{Op: "local error", Err: err})}return nil}// sendAlert sends a TLS alert message.// L < c.out.Mutex.func (c *Conn) sendAlert(err alert) 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 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.versif 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 += mdata = 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] = alertLevelErrorc.tmp[1] = byte(err.(alert))c.writeRecord(recordTypeAlert, c.tmp[0:2])c.err = &net.OpError{Op: "local error", Err: 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{}, error) {for c.hand.Len() < 4 {if c.err != nil {return nil, c.err}if err := c.readRecord(recordTypeHandshake); err != nil {return nil, err}}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}if err := c.readRecord(recordTypeHandshake); err != nil {return nil, err}}data = c.hand.Next(4 + n)var m handshakeMessageswitch data[0] {case typeClientHello:m = new(clientHelloMsg)case typeServerHello:m = new(serverHelloMsg)case typeCertificate:m = new(certificateMsg)case typeCertificateRequest:m = new(certificateRequestMsg)case typeCertificateStatus:m = new(certificateStatusMsg)case typeServerKeyExchange:m = new(serverKeyExchangeMsg)case typeServerHelloDone:m = new(serverHelloDoneMsg)case typeClientKeyExchange:m = new(clientKeyExchangeMsg)case typeCertificateVerify:m = new(certificateVerifyMsg)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 = append([]byte(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 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 a net.Error with Timeout() == true// after a fixed time limit; see SetDeadline and SetReadDeadline.func (c *Conn) Read(b []byte) (n int, err error) {if err = c.Handshake(); err != nil {return}c.in.Lock()defer c.in.Unlock()for c.input == nil && c.err == nil {if err := c.readRecord(recordTypeApplicationData); err != nil {// Soft error, like EAGAINreturn 0, err}}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() error {var alertErr errorc.handshakeMutex.Lock()defer c.handshakeMutex.Unlock()if c.handshakeComplete {alertErr = c.sendAlert(alertCloseNotify)}if err := c.conn.Close(); err != nil {return err}return alertErr}// Handshake runs the client or server handshake// protocol if it has not yet been run.// Most uses of this package need not call Handshake// explicitly: the first Read or Write will call it automatically.func (c *Conn) Handshake() 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 ConnectionStatestate.HandshakeComplete = c.handshakeCompleteif c.handshakeComplete {state.NegotiatedProtocol = c.clientProtocolstate.NegotiatedProtocolIsMutual = !c.clientProtocolFallbackstate.CipherSuite = c.cipherSuitestate.PeerCertificates = c.peerCertificatesstate.VerifiedChains = c.verifiedChainsstate.ServerName = c.serverName}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}// VerifyHostname checks that the peer certificate chain is valid for// connecting to host. If so, it returns nil; if not, it returns an error// describing the problem.func (c *Conn) VerifyHostname(host string) error {c.handshakeMutex.Lock()defer c.handshakeMutex.Unlock()if !c.isClient {return errors.New("VerifyHostname called on TLS server connection")}if !c.handshakeComplete {return errors.New("TLS handshake has not yet been performed")}return c.peerCertificates[0].VerifyHostname(host)}
