536df07f72
parsing and printing to new syntax. Use -oldparser to parse the old syntax, use -oldprinter to print the old syntax. 2) Change default gofmt formatting settings to use tabs for indentation only and to use spaces for alignment. This will make the code alignment insensitive to an editor's tabwidth. Use -spaces=false to use tabs for alignment. 3) Manually changed src/exp/parser/parser_test.go so that it doesn't try to parse the parser's source files using the old syntax (they have new syntax now). 4) gofmt -w src misc test/bench 1st set of files. R=rsc CC=agl, golang-dev, iant, ken2, r https://golang.org/cl/180047
171 lines
4.3 KiB
Go
171 lines
4.3 KiB
Go
// 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.
|
|
|
|
package tls
|
|
|
|
import (
|
|
"fmt"
|
|
"hash"
|
|
"io"
|
|
)
|
|
|
|
// writerEnableApplicationData is a message which instructs recordWriter to
|
|
// start reading and transmitting data from the application data channel.
|
|
type writerEnableApplicationData struct{}
|
|
|
|
// writerChangeCipherSpec updates the encryption and MAC functions and resets
|
|
// the sequence count.
|
|
type writerChangeCipherSpec struct {
|
|
encryptor encryptor
|
|
mac hash.Hash
|
|
}
|
|
|
|
// writerSetVersion sets the version number bytes that we included in the
|
|
// record header for future records.
|
|
type writerSetVersion struct {
|
|
major, minor uint8
|
|
}
|
|
|
|
// A recordWriter accepts messages from the handshake processor and
|
|
// application data. It writes them to the outgoing connection and blocks on
|
|
// writing. It doesn't read from the application data channel until the
|
|
// handshake processor has signaled that the handshake is complete.
|
|
type recordWriter struct {
|
|
writer io.Writer
|
|
encryptor encryptor
|
|
mac hash.Hash
|
|
seqNum uint64
|
|
major, minor uint8
|
|
shutdown bool
|
|
appChan <-chan []byte
|
|
controlChan <-chan interface{}
|
|
header [13]byte
|
|
}
|
|
|
|
func (w *recordWriter) loop(writer io.Writer, appChan <-chan []byte, controlChan <-chan interface{}) {
|
|
w.writer = writer
|
|
w.encryptor = nop{}
|
|
w.mac = nop{}
|
|
w.appChan = appChan
|
|
w.controlChan = controlChan
|
|
|
|
for !w.shutdown {
|
|
msg := <-controlChan
|
|
if _, ok := msg.(writerEnableApplicationData); ok {
|
|
break
|
|
}
|
|
w.processControlMessage(msg)
|
|
}
|
|
|
|
for !w.shutdown {
|
|
// Always process control messages first.
|
|
if controlMsg, ok := <-controlChan; ok {
|
|
w.processControlMessage(controlMsg)
|
|
continue
|
|
}
|
|
|
|
select {
|
|
case controlMsg := <-controlChan:
|
|
w.processControlMessage(controlMsg)
|
|
case appMsg := <-appChan:
|
|
w.processAppMessage(appMsg)
|
|
}
|
|
}
|
|
|
|
if !closed(appChan) {
|
|
go func() {
|
|
for _ = range appChan {
|
|
}
|
|
}()
|
|
}
|
|
if !closed(controlChan) {
|
|
go func() {
|
|
for _ = range controlChan {
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
// fillMACHeader generates a MAC header. See RFC 4346, section 6.2.3.1.
|
|
func fillMACHeader(header *[13]byte, seqNum uint64, length int, r *record) {
|
|
header[0] = uint8(seqNum >> 56)
|
|
header[1] = uint8(seqNum >> 48)
|
|
header[2] = uint8(seqNum >> 40)
|
|
header[3] = uint8(seqNum >> 32)
|
|
header[4] = uint8(seqNum >> 24)
|
|
header[5] = uint8(seqNum >> 16)
|
|
header[6] = uint8(seqNum >> 8)
|
|
header[7] = uint8(seqNum)
|
|
header[8] = uint8(r.contentType)
|
|
header[9] = r.major
|
|
header[10] = r.minor
|
|
header[11] = uint8(length >> 8)
|
|
header[12] = uint8(length)
|
|
}
|
|
|
|
func (w *recordWriter) writeRecord(r *record) {
|
|
w.mac.Reset()
|
|
|
|
fillMACHeader(&w.header, w.seqNum, len(r.payload), r)
|
|
|
|
w.mac.Write(w.header[0:13])
|
|
w.mac.Write(r.payload)
|
|
macBytes := w.mac.Sum()
|
|
|
|
w.encryptor.XORKeyStream(r.payload)
|
|
w.encryptor.XORKeyStream(macBytes)
|
|
|
|
length := len(r.payload) + len(macBytes)
|
|
w.header[11] = uint8(length >> 8)
|
|
w.header[12] = uint8(length)
|
|
w.writer.Write(w.header[8:13])
|
|
w.writer.Write(r.payload)
|
|
w.writer.Write(macBytes)
|
|
|
|
w.seqNum++
|
|
}
|
|
|
|
func (w *recordWriter) processControlMessage(controlMsg interface{}) {
|
|
if controlMsg == nil {
|
|
w.shutdown = true
|
|
return
|
|
}
|
|
|
|
switch msg := controlMsg.(type) {
|
|
case writerChangeCipherSpec:
|
|
w.writeRecord(&record{recordTypeChangeCipherSpec, w.major, w.minor, []byte{0x01}})
|
|
w.encryptor = msg.encryptor
|
|
w.mac = msg.mac
|
|
w.seqNum = 0
|
|
case writerSetVersion:
|
|
w.major = msg.major
|
|
w.minor = msg.minor
|
|
case alert:
|
|
w.writeRecord(&record{recordTypeAlert, w.major, w.minor, []byte{byte(msg.level), byte(msg.error)}})
|
|
case handshakeMessage:
|
|
// TODO(agl): marshal may return a slice too large for a single record.
|
|
w.writeRecord(&record{recordTypeHandshake, w.major, w.minor, msg.marshal()})
|
|
default:
|
|
fmt.Printf("processControlMessage: unknown %#v\n", msg)
|
|
}
|
|
}
|
|
|
|
func (w *recordWriter) processAppMessage(appMsg []byte) {
|
|
if closed(w.appChan) {
|
|
w.writeRecord(&record{recordTypeApplicationData, w.major, w.minor, []byte{byte(alertCloseNotify)}})
|
|
w.shutdown = true
|
|
return
|
|
}
|
|
|
|
var done int
|
|
for done < len(appMsg) {
|
|
todo := len(appMsg)
|
|
if todo > maxTLSPlaintext {
|
|
todo = maxTLSPlaintext
|
|
}
|
|
w.writeRecord(&record{recordTypeApplicationData, w.major, w.minor, appMsg[done : done+todo]})
|
|
done += todo
|
|
}
|
|
}
|