blob: 5fbf850daa0dda523da693501ee9f9f88057ef3b [file] [log] [blame]
Adam Langley950f2632009-11-05 16:43:29 -08001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// This package partially implements the TLS 1.1 protocol, as specified in RFC 4346.
6package tls
7
8import (
Robert Griesemer5a1d3322009-12-15 15:33:31 -08009 "io"
10 "os"
11 "net"
12 "time"
Adam Langley950f2632009-11-05 16:43:29 -080013)
14
15// A Conn represents a secure connection.
16type Conn struct {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080017 net.Conn
18 writeChan chan<- []byte
19 readChan <-chan []byte
20 requestChan chan<- interface{}
21 readBuf []byte
22 eof bool
23 readTimeout, writeTimeout int64
Adam Langley950f2632009-11-05 16:43:29 -080024}
25
26func timeout(c chan<- bool, nsecs int64) {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080027 time.Sleep(nsecs)
28 c <- true
Adam Langley950f2632009-11-05 16:43:29 -080029}
30
31func (tls *Conn) Read(p []byte) (int, os.Error) {
32 if len(tls.readBuf) == 0 {
33 if tls.eof {
Robert Griesemer40621d52009-11-09 12:07:39 -080034 return 0, os.EOF
Adam Langley950f2632009-11-05 16:43:29 -080035 }
36
Robert Griesemer5a1d3322009-12-15 15:33:31 -080037 var timeoutChan chan bool
Adam Langley950f2632009-11-05 16:43:29 -080038 if tls.readTimeout > 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080039 timeoutChan = make(chan bool)
40 go timeout(timeoutChan, tls.readTimeout)
Adam Langley950f2632009-11-05 16:43:29 -080041 }
42
43 select {
44 case b := <-tls.readChan:
Robert Griesemer40621d52009-11-09 12:07:39 -080045 tls.readBuf = b
Adam Langley950f2632009-11-05 16:43:29 -080046 case <-timeoutChan:
Robert Griesemer40621d52009-11-09 12:07:39 -080047 return 0, os.EAGAIN
Adam Langley950f2632009-11-05 16:43:29 -080048 }
49
50 // TLS distinguishes between orderly closes and truncations. An
51 // orderly close is represented by a zero length slice.
52 if closed(tls.readChan) {
Robert Griesemer40621d52009-11-09 12:07:39 -080053 return 0, io.ErrUnexpectedEOF
Adam Langley950f2632009-11-05 16:43:29 -080054 }
55 if len(tls.readBuf) == 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080056 tls.eof = true
57 return 0, os.EOF
Adam Langley950f2632009-11-05 16:43:29 -080058 }
59 }
60
Robert Griesemer5a1d3322009-12-15 15:33:31 -080061 n := copy(p, tls.readBuf)
62 tls.readBuf = tls.readBuf[n:]
63 return n, nil
Adam Langley950f2632009-11-05 16:43:29 -080064}
65
66func (tls *Conn) Write(p []byte) (int, os.Error) {
67 if tls.eof || closed(tls.readChan) {
Robert Griesemer40621d52009-11-09 12:07:39 -080068 return 0, os.EOF
Adam Langley950f2632009-11-05 16:43:29 -080069 }
70
Robert Griesemer5a1d3322009-12-15 15:33:31 -080071 var timeoutChan chan bool
Adam Langley950f2632009-11-05 16:43:29 -080072 if tls.writeTimeout > 0 {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080073 timeoutChan = make(chan bool)
74 go timeout(timeoutChan, tls.writeTimeout)
Adam Langley950f2632009-11-05 16:43:29 -080075 }
76
77 select {
78 case tls.writeChan <- p:
79 case <-timeoutChan:
Robert Griesemer40621d52009-11-09 12:07:39 -080080 return 0, os.EAGAIN
Adam Langley950f2632009-11-05 16:43:29 -080081 }
82
Robert Griesemer5a1d3322009-12-15 15:33:31 -080083 return len(p), nil
Adam Langley950f2632009-11-05 16:43:29 -080084}
85
86func (tls *Conn) Close() os.Error {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080087 close(tls.writeChan)
88 close(tls.requestChan)
89 tls.eof = true
90 return nil
Adam Langley950f2632009-11-05 16:43:29 -080091}
92
93func (tls *Conn) SetTimeout(nsec int64) os.Error {
Robert Griesemer5a1d3322009-12-15 15:33:31 -080094 tls.readTimeout = nsec
95 tls.writeTimeout = nsec
96 return nil
Adam Langley950f2632009-11-05 16:43:29 -080097}
98
99func (tls *Conn) SetReadTimeout(nsec int64) os.Error {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800100 tls.readTimeout = nsec
101 return nil
Adam Langley950f2632009-11-05 16:43:29 -0800102}
103
104func (tls *Conn) SetWriteTimeout(nsec int64) os.Error {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800105 tls.writeTimeout = nsec
106 return nil
Adam Langley950f2632009-11-05 16:43:29 -0800107}
108
109func (tls *Conn) GetConnectionState() ConnectionState {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800110 replyChan := make(chan ConnectionState)
111 tls.requestChan <- getConnectionState{replyChan}
112 return <-replyChan
Adam Langley950f2632009-11-05 16:43:29 -0800113}
114
Adam Langley6e0842d2009-11-21 15:53:03 -0800115func (tls *Conn) WaitConnectionState() ConnectionState {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800116 replyChan := make(chan ConnectionState)
117 tls.requestChan <- waitConnectionState{replyChan}
118 return <-replyChan
Adam Langley6e0842d2009-11-21 15:53:03 -0800119}
120
121type handshaker interface {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800122 loop(writeChan chan<- interface{}, controlChan chan<- interface{}, msgChan <-chan interface{}, config *Config)
Adam Langley6e0842d2009-11-21 15:53:03 -0800123}
124
Adam Langley950f2632009-11-05 16:43:29 -0800125// Server establishes a secure connection over the given connection and acts
126// as a TLS server.
Adam Langley6e0842d2009-11-21 15:53:03 -0800127func startTLSGoroutines(conn net.Conn, h handshaker, config *Config) *Conn {
Russ Cox99d258a2010-04-05 14:38:02 -0700128 if config == nil {
129 config = defaultConfig()
130 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800131 tls := new(Conn)
132 tls.Conn = conn
Adam Langley950f2632009-11-05 16:43:29 -0800133
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800134 writeChan := make(chan []byte)
135 readChan := make(chan []byte)
136 requestChan := make(chan interface{})
Adam Langley950f2632009-11-05 16:43:29 -0800137
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800138 tls.writeChan = writeChan
139 tls.readChan = readChan
140 tls.requestChan = requestChan
Adam Langley950f2632009-11-05 16:43:29 -0800141
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800142 handshakeWriterChan := make(chan interface{})
143 processorHandshakeChan := make(chan interface{})
144 handshakeProcessorChan := make(chan interface{})
145 readerProcessorChan := make(chan *record)
Adam Langley950f2632009-11-05 16:43:29 -0800146
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800147 go new(recordWriter).loop(conn, writeChan, handshakeWriterChan)
148 go recordReader(readerProcessorChan, conn)
149 go new(recordProcessor).loop(readChan, requestChan, handshakeProcessorChan, readerProcessorChan, processorHandshakeChan)
150 go h.loop(handshakeWriterChan, handshakeProcessorChan, processorHandshakeChan, config)
Adam Langley950f2632009-11-05 16:43:29 -0800151
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800152 return tls
Adam Langley950f2632009-11-05 16:43:29 -0800153}
154
Adam Langley6e0842d2009-11-21 15:53:03 -0800155func Server(conn net.Conn, config *Config) *Conn {
156 return startTLSGoroutines(conn, new(serverHandshake), config)
157}
158
159func Client(conn net.Conn, config *Config) *Conn {
160 return startTLSGoroutines(conn, new(clientHandshake), config)
161}
162
Adam Langley950f2632009-11-05 16:43:29 -0800163type Listener struct {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800164 listener net.Listener
165 config *Config
Adam Langley950f2632009-11-05 16:43:29 -0800166}
167
Adam Langley3c6bf092009-12-28 11:40:01 -0800168func (l *Listener) Accept() (c net.Conn, err os.Error) {
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800169 c, err = l.listener.Accept()
Adam Langley950f2632009-11-05 16:43:29 -0800170 if err != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800171 return
Adam Langley950f2632009-11-05 16:43:29 -0800172 }
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800173 c = Server(c, l.config)
174 return
Adam Langley950f2632009-11-05 16:43:29 -0800175}
176
Adam Langley3c6bf092009-12-28 11:40:01 -0800177func (l *Listener) Close() os.Error { return l.listener.Close() }
Adam Langley950f2632009-11-05 16:43:29 -0800178
Adam Langley3c6bf092009-12-28 11:40:01 -0800179func (l *Listener) Addr() net.Addr { return l.listener.Addr() }
Adam Langley950f2632009-11-05 16:43:29 -0800180
181// NewListener creates a Listener which accepts connections from an inner
182// Listener and wraps each connection with Server.
Adam Langley3c6bf092009-12-28 11:40:01 -0800183func NewListener(listener net.Listener, config *Config) (l *Listener) {
Russ Cox99d258a2010-04-05 14:38:02 -0700184 if config == nil {
185 config = defaultConfig()
186 }
Adam Langley3c6bf092009-12-28 11:40:01 -0800187 l = new(Listener)
Robert Griesemer5a1d3322009-12-15 15:33:31 -0800188 l.listener = listener
189 l.config = config
190 return
Adam Langley950f2632009-11-05 16:43:29 -0800191}
Russ Cox99d258a2010-04-05 14:38:02 -0700192
193func Listen(network, laddr string) (net.Listener, os.Error) {
194 l, err := net.Listen(network, laddr)
195 if err != nil {
196 return nil, err
197 }
198 return NewListener(l, nil), nil
199}
200
201func Dial(network, laddr, raddr string) (net.Conn, os.Error) {
202 c, err := net.Dial(network, laddr, raddr)
203 if err != nil {
204 return nil, err
205 }
206 return Client(c, nil), nil
207}