From 9c63ad9791ca6a7e9d7996d78d1b97b279ccf97e Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Thu, 5 Nov 2009 16:43:29 -0800 Subject: [PATCH] crypto/tls (part 4/5) R=rsc CC=go-dev http://go/go-review/1019002 --- Makefile | 19 ++++++ tls.go | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 Makefile create mode 100644 tls.go diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dd3df29 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +# Copyright 2009 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. + +include $(GOROOT)/src/Make.$(GOARCH) + +TARG=crypto/tls +GOFILES=\ + alert.go\ + common.go\ + handshake_messages.go\ + handshake_server.go\ + prf.go\ + record_process.go\ + record_read.go\ + record_write.go\ + tls.go\ + +include $(GOROOT)/src/Make.pkg diff --git a/tls.go b/tls.go new file mode 100644 index 0000000..13d8fd7 --- /dev/null +++ b/tls.go @@ -0,0 +1,172 @@ +// Copyright 2009 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. + +// This package partially implements the TLS 1.1 protocol, as specified in RFC 4346. +package tls + +import ( + "bytes"; + "io"; + "os"; + "net"; + "time"; +) + +// A Conn represents a secure connection. +type Conn struct { + net.Conn; + writeChan chan<- []byte; + readChan <-chan []byte; + requestChan chan<- interface{}; + readBuf []byte; + eof bool; + readTimeout, writeTimeout int64; +} + +func timeout(c chan<- bool, nsecs int64) { + time.Sleep(nsecs); + c <- true; +} + +func (tls *Conn) Read(p []byte) (int, os.Error) { + if len(tls.readBuf) == 0 { + if tls.eof { + return 0, os.EOF; + } + + var timeoutChan chan bool; + if tls.readTimeout > 0 { + timeoutChan = make(chan bool); + go timeout(timeoutChan, tls.readTimeout); + } + + select { + case b := <-tls.readChan: + tls.readBuf = b; + case <-timeoutChan: + return 0, os.EAGAIN; + } + + // TLS distinguishes between orderly closes and truncations. An + // orderly close is represented by a zero length slice. + if closed(tls.readChan) { + return 0, io.ErrUnexpectedEOF; + } + if len(tls.readBuf) == 0 { + tls.eof = true; + return 0, os.EOF; + } + } + + n := bytes.Copy(p, tls.readBuf); + tls.readBuf = tls.readBuf[n:len(tls.readBuf)]; + return n, nil; +} + +func (tls *Conn) Write(p []byte) (int, os.Error) { + if tls.eof || closed(tls.readChan) { + return 0, os.EOF; + } + + var timeoutChan chan bool; + if tls.writeTimeout > 0 { + timeoutChan = make(chan bool); + go timeout(timeoutChan, tls.writeTimeout); + } + + select { + case tls.writeChan <- p: + case <-timeoutChan: + return 0, os.EAGAIN; + } + + return len(p), nil; +} + +func (tls *Conn) Close() os.Error { + close(tls.writeChan); + close(tls.requestChan); + tls.eof = true; + return nil; +} + +func (tls *Conn) SetTimeout(nsec int64) os.Error { + tls.readTimeout = nsec; + tls.writeTimeout = nsec; + return nil; +} + +func (tls *Conn) SetReadTimeout(nsec int64) os.Error { + tls.readTimeout = nsec; + return nil; +} + +func (tls *Conn) SetWriteTimeout(nsec int64) os.Error { + tls.writeTimeout = nsec; + return nil; +} + +func (tls *Conn) GetConnectionState() ConnectionState { + replyChan := make(chan ConnectionState); + tls.requestChan <- getConnectionState{replyChan}; + return <-replyChan; +} + +// Server establishes a secure connection over the given connection and acts +// as a TLS server. +func Server(conn net.Conn, config *Config) *Conn { + tls := new(Conn); + tls.Conn = conn; + + writeChan := make(chan []byte); + readChan := make(chan []byte); + requestChan := make(chan interface{}); + + tls.writeChan = writeChan; + tls.readChan = readChan; + tls.requestChan = requestChan; + + handshakeWriterChan := make(chan interface{}); + processorHandshakeChan := make(chan interface{}); + handshakeProcessorChan := make(chan interface{}); + readerProcessorChan := make(chan *record); + + go new(recordWriter).loop(conn, writeChan, handshakeWriterChan); + go recordReader(readerProcessorChan, conn); + go new(recordProcessor).loop(readChan, requestChan, handshakeProcessorChan, readerProcessorChan, processorHandshakeChan); + go new(serverHandshake).loop(handshakeWriterChan, handshakeProcessorChan, processorHandshakeChan, config); + + return tls; +} + +type Listener struct { + listener net.Listener; + config *Config; +} + +func (l Listener) Accept() (c net.Conn, err os.Error) { + c, err = l.listener.Accept(); + if err != nil { + return; + } + + c = Server(c, l.config); + return; +} + +func (l Listener) Close() os.Error { + return l.listener.Close(); +} + +func (l Listener) Addr() net.Addr { + return l.listener.Addr(); +} + +// NewListener creates a Listener which accepts connections from an inner +// Listener and wraps each connection with Server. +func NewListener(listener net.Listener, config *Config) (l Listener) { + l.listener = listener; + l.config = config; + return; +}