crypto/tls: support TLS 1.1.

The significant change between TLS 1.0 and 1.1 is the addition of an explicit IV in the case of CBC encrypted records. Support for TLS 1.1 is needed in order to support TLS 1.2.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/7880043
diff --git a/src/pkg/crypto/cipher/cbc.go b/src/pkg/crypto/cipher/cbc.go
index 913a564..4189677 100644
--- a/src/pkg/crypto/cipher/cbc.go
+++ b/src/pkg/crypto/cipher/cbc.go
@@ -61,6 +61,13 @@
 	}
 }
 
+func (x *cbcEncrypter) SetIV(iv []byte) {
+	if len(iv) != len(x.iv) {
+		panic("cipher: incorrect length IV")
+	}
+	copy(x.iv, iv)
+}
+
 type cbcDecrypter cbc
 
 // NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining
@@ -94,3 +101,10 @@
 		dst = dst[x.blockSize:]
 	}
 }
+
+func (x *cbcDecrypter) SetIV(iv []byte) {
+	if len(iv) != len(x.iv) {
+		panic("cipher: incorrect length IV")
+	}
+	copy(x.iv, iv)
+}
diff --git a/src/pkg/crypto/tls/cipher_suites.go b/src/pkg/crypto/tls/cipher_suites.go
index a647e19..11181e4 100644
--- a/src/pkg/crypto/tls/cipher_suites.go
+++ b/src/pkg/crypto/tls/cipher_suites.go
@@ -85,7 +85,7 @@
 
 // macSHA1 returns a macFunction for the given protocol version.
 func macSHA1(version uint16, key []byte) macFunction {
-	if version == versionSSL30 {
+	if version == VersionSSL30 {
 		mac := ssl30MAC{
 			h:   sha1.New(),
 			key: make([]byte, len(key)),
@@ -98,7 +98,7 @@
 
 type macFunction interface {
 	Size() int
-	MAC(digestBuf, seq, data []byte) []byte
+	MAC(digestBuf, seq, header, data []byte) []byte
 }
 
 // ssl30MAC implements the SSLv3 MAC function, as defined in
@@ -116,7 +116,7 @@
 
 var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}
 
-func (s ssl30MAC) MAC(digestBuf, seq, record []byte) []byte {
+func (s ssl30MAC) MAC(digestBuf, seq, header, data []byte) []byte {
 	padLength := 48
 	if s.h.Size() == 20 {
 		padLength = 40
@@ -126,9 +126,9 @@
 	s.h.Write(s.key)
 	s.h.Write(ssl30Pad1[:padLength])
 	s.h.Write(seq)
-	s.h.Write(record[:1])
-	s.h.Write(record[3:5])
-	s.h.Write(record[recordHeaderLen:])
+	s.h.Write(header[:1])
+	s.h.Write(header[3:5])
+	s.h.Write(data)
 	digestBuf = s.h.Sum(digestBuf[:0])
 
 	s.h.Reset()
@@ -147,10 +147,11 @@
 	return s.h.Size()
 }
 
-func (s tls10MAC) MAC(digestBuf, seq, record []byte) []byte {
+func (s tls10MAC) MAC(digestBuf, seq, header, data []byte) []byte {
 	s.h.Reset()
 	s.h.Write(seq)
-	s.h.Write(record)
+	s.h.Write(header)
+	s.h.Write(data)
 	return s.h.Sum(digestBuf[:0])
 }
 
diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go
index f86c90d..fb995a1 100644
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -15,16 +15,19 @@
 )
 
 const (
+	VersionSSL30 = 0x0300
+	VersionTLS10 = 0x0301
+	VersionTLS11 = 0x0302
+)
+
+const (
 	maxPlaintext    = 16384        // maximum plaintext payload length
 	maxCiphertext   = 16384 + 2048 // maximum ciphertext payload length
 	recordHeaderLen = 5            // record header length
 	maxHandshake    = 65536        // maximum handshake we support (protocol max is 16 MB)
 
-	versionSSL30 = 0x0300
-	versionTLS10 = 0x0301
-
-	minVersion = versionSSL30
-	maxVersion = versionTLS10
+	minVersion = VersionSSL30
+	maxVersion = VersionTLS11
 )
 
 // TLS record types.
@@ -204,6 +207,15 @@
 	// connections using that key are compromised.
 	SessionTicketKey [32]byte
 
+	// MinVersion contains the minimum SSL/TLS version that is acceptable.
+	// If zero, then SSLv3 is taken as the minimum.
+	MinVersion uint16
+
+	// MaxVersion contains the maximum SSL/TLS version that is acceptable.
+	// If zero, then the maximum version supported by this package is used,
+	// which is currently TLS 1.1.
+	MaxVersion uint16
+
 	serverInitOnce sync.Once // guards calling (*Config).serverInit
 }
 
@@ -248,6 +260,35 @@
 	return s
 }
 
+func (c *Config) minVersion() uint16 {
+	if c == nil || c.MinVersion == 0 {
+		return minVersion
+	}
+	return c.MinVersion
+}
+
+func (c *Config) maxVersion() uint16 {
+	if c == nil || c.MaxVersion == 0 {
+		return maxVersion
+	}
+	return c.MaxVersion
+}
+
+// mutualVersion returns the protocol version to use given the advertised
+// version of the peer.
+func (c *Config) mutualVersion(vers uint16) (uint16, bool) {
+	minVersion := c.minVersion()
+	maxVersion := c.maxVersion()
+
+	if vers < minVersion {
+		return 0, false
+	}
+	if vers > maxVersion {
+		vers = maxVersion
+	}
+	return vers, true
+}
+
 // getCertificateForName returns the best certificate for the given name,
 // defaulting to the first element of c.Certificates if there are no good
 // options.
@@ -327,18 +368,6 @@
 	unmarshal([]byte) bool
 }
 
-// mutualVersion returns the protocol version to use given the advertised
-// version of the peer.
-func mutualVersion(vers uint16) (uint16, bool) {
-	if vers < minVersion {
-		return 0, false
-	}
-	if vers > maxVersion {
-		vers = maxVersion
-	}
-	return vers, true
-}
-
 var emptyConfig Config
 
 func defaultConfig() *Config {
diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go
index 9660553..6cf8bd6 100644
--- a/src/pkg/crypto/tls/conn.go
+++ b/src/pkg/crypto/tls/conn.go
@@ -229,8 +229,16 @@
 	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) {
+// cbcMode is an interface for block ciphers using cipher block chaining.
+type cbcMode interface {
+	cipher.BlockMode
+	SetIV([]byte)
+}
+
+// decrypt checks and strips the mac and decrypts the data in b. Returns a
+// success boolean, the number of bytes to skip from the start of the record in
+// order to get the application payload, and an optional alert value.
+func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert) {
 	// pull out payload
 	payload := b.data[recordHeaderLen:]
 
@@ -240,26 +248,34 @@
 	}
 
 	paddingGood := byte(255)
+	explicitIVLen := 0
 
 	// decrypt
 	if hc.cipher != nil {
 		switch c := hc.cipher.(type) {
 		case cipher.Stream:
 			c.XORKeyStream(payload, payload)
-		case cipher.BlockMode:
+		case cbcMode:
 			blockSize := c.BlockSize()
-
-			if len(payload)%blockSize != 0 || len(payload) < roundUp(macSize+1, blockSize) {
-				return false, alertBadRecordMAC
+			if hc.version >= VersionTLS11 {
+				explicitIVLen = blockSize
 			}
 
+			if len(payload)%blockSize != 0 || len(payload) < roundUp(explicitIVLen+macSize+1, blockSize) {
+				return false, 0, alertBadRecordMAC
+			}
+
+			if explicitIVLen > 0 {
+				c.SetIV(payload[:explicitIVLen])
+				payload = payload[explicitIVLen:]
+			}
 			c.CryptBlocks(payload, payload)
-			if hc.version == versionSSL30 {
+			if hc.version == VersionSSL30 {
 				payload, paddingGood = removePaddingSSL30(payload)
 			} else {
 				payload, paddingGood = removePadding(payload)
 			}
-			b.resize(recordHeaderLen + len(payload))
+			b.resize(recordHeaderLen + explicitIVLen + len(payload))
 
 			// note that we still have a timing side-channel in the
 			// MAC check, below. An attacker can align the record
@@ -279,25 +295,25 @@
 	// check, strip mac
 	if hc.mac != nil {
 		if len(payload) < macSize {
-			return false, alertBadRecordMAC
+			return false, 0, alertBadRecordMAC
 		}
 
 		// strip mac off payload, b.data
 		n := len(payload) - macSize
 		b.data[3] = byte(n >> 8)
 		b.data[4] = byte(n)
-		b.resize(recordHeaderLen + n)
+		b.resize(recordHeaderLen + explicitIVLen + n)
 		remoteMAC := payload[n:]
-		localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data)
+		localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], payload[:n])
 		hc.incSeq()
 
 		if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 {
-			return false, alertBadRecordMAC
+			return false, 0, alertBadRecordMAC
 		}
 		hc.inDigestBuf = localMAC
 	}
 
-	return true, 0
+	return true, recordHeaderLen + explicitIVLen, 0
 }
 
 // padToBlockSize calculates the needed padding block, if any, for a payload.
@@ -318,10 +334,10 @@
 }
 
 // encrypt encrypts and macs the data in b.
-func (hc *halfConn) encrypt(b *block) (bool, alert) {
+func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
 	// mac
 	if hc.mac != nil {
-		mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data)
+		mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:])
 		hc.incSeq()
 
 		n := len(b.data)
@@ -337,11 +353,16 @@
 		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)
+		case cbcMode:
+			blockSize := c.BlockSize()
+			if explicitIVLen > 0 {
+				c.SetIV(payload[:explicitIVLen])
+				payload = payload[explicitIVLen:]
+			}
+			prefix, finalBlock := padToBlockSize(payload, blockSize)
+			b.resize(recordHeaderLen + explicitIVLen + len(prefix) + len(finalBlock))
+			c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix)
+			c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock)
 		default:
 			panic("unknown cipher type")
 		}
@@ -534,10 +555,11 @@
 
 	// Process message.
 	b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
-	b.off = recordHeaderLen
-	if ok, err := c.in.decrypt(b); !ok {
+	ok, off, err := c.in.decrypt(b)
+	if !ok {
 		return c.sendAlert(err)
 	}
+	b.off = off
 	data := b.data[b.off:]
 	if len(data) > maxPlaintext {
 		c.sendAlert(alertRecordOverflow)
@@ -637,18 +659,35 @@
 		if m > maxPlaintext {
 			m = maxPlaintext
 		}
-		b.resize(recordHeaderLen + m)
+		explicitIVLen := 0
+
+		var cbc cbcMode
+		if c.out.version >= VersionTLS11 {
+			var ok bool
+			if cbc, ok = c.out.cipher.(cbcMode); ok {
+				explicitIVLen = cbc.BlockSize()
+			}
+		}
+		b.resize(recordHeaderLen + explicitIVLen + m)
 		b.data[0] = byte(typ)
 		vers := c.vers
 		if vers == 0 {
-			vers = maxVersion
+			// Some TLS servers fail if the record version is
+			// greater than TLS 1.0 for the initial ClientHello.
+			vers = VersionTLS10
 		}
 		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)
+		if explicitIVLen > 0 {
+			explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
+			if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
+				break
+			}
+		}
+		copy(b.data[recordHeaderLen+explicitIVLen:], data)
+		c.out.encrypt(b, explicitIVLen)
 		_, err = c.conn.Write(b.data)
 		if err != nil {
 			break
@@ -768,7 +807,7 @@
 	// http://www.imperialviolet.org/2012/01/15/beastfollowup.html
 
 	var m int
-	if len(b) > 1 && c.vers <= versionTLS10 {
+	if len(b) > 1 && c.vers <= VersionTLS10 {
 		if _, ok := c.out.cipher.(cipher.BlockMode); ok {
 			n, err := c.writeRecord(recordTypeApplicationData, b[:1])
 			if err != nil {
diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go
index 4d09cfd..e8196fb 100644
--- a/src/pkg/crypto/tls/handshake_client.go
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -16,14 +16,14 @@
 )
 
 func (c *Conn) clientHandshake() error {
-	finishedHash := newFinishedHash(versionTLS10)
+	finishedHash := newFinishedHash(VersionTLS10)
 
 	if c.config == nil {
 		c.config = defaultConfig()
 	}
 
 	hello := &clientHelloMsg{
-		vers:               maxVersion,
+		vers:               c.config.maxVersion(),
 		cipherSuites:       c.config.cipherSuites(),
 		compressionMethods: []uint8{compressionNone},
 		random:             make([]byte, 32),
@@ -58,8 +58,8 @@
 	}
 	finishedHash.Write(serverHello.marshal())
 
-	vers, ok := mutualVersion(serverHello.vers)
-	if !ok || vers < versionTLS10 {
+	vers, ok := c.config.mutualVersion(serverHello.vers)
+	if !ok || vers < VersionTLS10 {
 		// TLS 1.0 is the minimum version supported as a client.
 		return c.sendAlert(alertProtocolVersion)
 	}
diff --git a/src/pkg/crypto/tls/handshake_client_test.go b/src/pkg/crypto/tls/handshake_client_test.go
index 0a35393..031ad72 100644
--- a/src/pkg/crypto/tls/handshake_client_test.go
+++ b/src/pkg/crypto/tls/handshake_client_test.go
@@ -58,6 +58,13 @@
 	testClientScript(t, "Long client certificate chains", clientChainCertificateScript, &config)
 }
 
+func TestHandshakeClientTLS11(t *testing.T) {
+	var config = *testConfig
+	config.MaxVersion = VersionTLS11
+	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
+	testClientScript(t, "TLS11-ECDHE-AES", tls11ECDHEAESClientScript, &config)
+}
+
 var connect = flag.Bool("connect", false, "connect to a TLS server on :10443")
 
 func TestRunClient(t *testing.T) {
@@ -1008,6 +1015,174 @@
 	},
 }
 
+var tls11ECDHEAESClientScript = [][]byte{
+	{
+		0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
+		0x46, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x13,
+		0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+		0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
+		0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
+	},
+	{
+		0x16, 0x03, 0x02, 0x00, 0x54, 0x02, 0x00, 0x00,
+		0x50, 0x03, 0x02, 0x51, 0x9f, 0xa2, 0x21, 0x1a,
+		0xb7, 0x75, 0x42, 0x69, 0xd3, 0x14, 0xdd, 0x05,
+		0x1e, 0xda, 0x13, 0x71, 0x8d, 0x6a, 0x45, 0x97,
+		0xcb, 0xee, 0x0e, 0x77, 0x01, 0x0d, 0x6e, 0xe5,
+		0x22, 0x70, 0x16, 0x20, 0x69, 0xfc, 0xa6, 0x9a,
+		0xe8, 0x21, 0xcc, 0x46, 0x65, 0x05, 0xb4, 0x48,
+		0x0f, 0x34, 0x63, 0x2c, 0xac, 0xa4, 0xf5, 0x4b,
+		0x64, 0xd1, 0x07, 0x13, 0xa7, 0xe4, 0x5b, 0xa3,
+		0x4d, 0x31, 0x41, 0x53, 0xc0, 0x13, 0x00, 0x00,
+		0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
+		0x02, 0x16, 0x03, 0x02, 0x02, 0x39, 0x0b, 0x00,
+		0x02, 0x35, 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f,
+		0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5,
+		0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
+		0xb1, 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92,
+		0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+		0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
+		0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+		0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+		0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+		0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+		0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+		0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+		0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+		0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+		0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
+		0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x30, 0x36,
+		0x31, 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17,
+		0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x36, 0x31,
+		0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45,
+		0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+		0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
+		0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
+		0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
+		0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
+		0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
+		0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
+		0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
+		0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30,
+		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+		0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,
+		0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3,
+		0xc3, 0x84, 0x27, 0x95, 0xff, 0x12, 0x31, 0x52,
+		0x0f, 0x15, 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80,
+		0xe6, 0x36, 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61,
+		0x8d, 0xe0, 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe,
+		0x55, 0x66, 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a,
+		0xfe, 0xa8, 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff,
+		0xee, 0xd7, 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f,
+		0xff, 0x2a, 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03,
+		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
+		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+		0x04, 0x16, 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a,
+		0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22,
+		0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b,
+		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+		0x6e, 0x30, 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97,
+		0x9a, 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba,
+		0x22, 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc,
+		0x2b, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
+		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1,
+		0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30,
+		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
+		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
+		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+		0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x85,
+		0x36, 0x40, 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4,
+		0x59, 0x9f, 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74,
+		0xec, 0x83, 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf,
+		0x39, 0xac, 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46,
+		0x1d, 0x99, 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b,
+		0x05, 0x08, 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92,
+		0xbb, 0x77, 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8,
+		0x5e, 0x9c, 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16,
+		0x03, 0x02, 0x00, 0x8b, 0x0c, 0x00, 0x00, 0x87,
+		0x03, 0x00, 0x17, 0x41, 0x04, 0x34, 0xde, 0x50,
+		0x32, 0x8f, 0x25, 0x6b, 0x37, 0x2c, 0x36, 0x24,
+		0x27, 0x0e, 0xf9, 0x67, 0xb4, 0xf8, 0x29, 0x1c,
+		0xa5, 0xa4, 0x59, 0x9a, 0xca, 0x40, 0x26, 0x15,
+		0x61, 0x72, 0x34, 0x4a, 0xd3, 0x0c, 0xac, 0x69,
+		0xcb, 0x2a, 0x9e, 0xf8, 0x80, 0xfb, 0x7a, 0xc4,
+		0xd4, 0x4b, 0x91, 0x1b, 0xbe, 0x24, 0x26, 0xad,
+		0x19, 0x24, 0xbe, 0x32, 0x58, 0xfb, 0xc7, 0x77,
+		0xce, 0x7e, 0x71, 0x51, 0x1a, 0x00, 0x40, 0x1a,
+		0x0b, 0xe8, 0x91, 0x84, 0x64, 0x54, 0xb6, 0x19,
+		0xe8, 0xd4, 0x43, 0x7c, 0x09, 0x0c, 0x2e, 0xba,
+		0x42, 0xb9, 0x74, 0xc3, 0x6c, 0x06, 0x9b, 0xa6,
+		0x7e, 0x92, 0xe9, 0xee, 0x7c, 0x74, 0xa9, 0xd3,
+		0x63, 0xf0, 0x16, 0x20, 0x60, 0x71, 0x8e, 0x24,
+		0xc7, 0x7f, 0xc5, 0x5b, 0x9c, 0x19, 0x0c, 0x80,
+		0x15, 0x61, 0xbf, 0xb6, 0xed, 0x5b, 0x7b, 0x90,
+		0xc5, 0x05, 0x13, 0x72, 0x45, 0x79, 0xdf, 0x16,
+		0x03, 0x02, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
+	},
+	{
+		0x16, 0x03, 0x02, 0x00, 0x46, 0x10, 0x00, 0x00,
+		0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
+		0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
+		0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
+		0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
+		0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
+		0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
+		0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
+		0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
+		0xdc, 0x5a, 0x89, 0x14, 0x03, 0x02, 0x00, 0x01,
+		0x01, 0x16, 0x03, 0x02, 0x00, 0x40, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x50,
+		0x32, 0x26, 0x51, 0xbd, 0xbd, 0x3c, 0x4f, 0x72,
+		0xbf, 0xbc, 0x91, 0x70, 0x4b, 0x5d, 0x43, 0x4a,
+		0x65, 0x26, 0x0d, 0xaa, 0xed, 0x00, 0x91, 0xaf,
+		0x4f, 0x47, 0x09, 0xaa, 0x79, 0xc4, 0x47, 0x21,
+		0x71, 0xd8, 0x2b, 0xc1, 0x51, 0xc8, 0xef, 0xed,
+		0x67, 0xde, 0x97, 0xef, 0x18, 0x53,
+	},
+	{
+		0x14, 0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03,
+		0x02, 0x00, 0x40, 0x72, 0x20, 0xbf, 0xd1, 0xbd,
+		0x83, 0x53, 0x57, 0xb0, 0x4e, 0xac, 0xba, 0x1a,
+		0x2b, 0x2d, 0xeb, 0x8a, 0x48, 0x17, 0xfa, 0x69,
+		0xf9, 0xb5, 0x94, 0x8e, 0x6f, 0x9c, 0xda, 0x59,
+		0xba, 0x6c, 0x7c, 0x82, 0xe2, 0x53, 0xa9, 0x46,
+		0xdc, 0x33, 0xa0, 0x9b, 0xf0, 0x1e, 0xf1, 0x53,
+		0x83, 0x48, 0xbf, 0x5e, 0xef, 0x03, 0x2b, 0x50,
+		0x7a, 0xa6, 0xf8, 0xc3, 0x9e, 0x24, 0x43, 0x3a,
+		0xdf, 0x44, 0x3e,
+	},
+	{
+		0x17, 0x03, 0x02, 0x00, 0x30, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x0b, 0x8f,
+		0x6b, 0xf9, 0xd3, 0x9f, 0x2b, 0x49, 0xe0, 0x62,
+		0x9a, 0x0b, 0x3e, 0xa2, 0x72, 0x8b, 0x96, 0x0c,
+		0x41, 0x09, 0x95, 0x9e, 0x6b, 0x26, 0xa1, 0x46,
+		0xca, 0xb8, 0xb6, 0xd2, 0xd4, 0x15, 0x03, 0x02,
+		0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0xa0, 0xd4, 0x84, 0xc6, 0x7e, 0x1c,
+		0x2f, 0xbd, 0x6b, 0x45, 0x31, 0x1d, 0x7d, 0x8f,
+		0x31, 0x39, 0x5a, 0x4e, 0xaa, 0xf1, 0x0a, 0x8a,
+		0x6c, 0x33, 0x59, 0x19, 0xd8, 0x75, 0x80, 0xab,
+		0x93, 0x81,
+	},
+}
+
 var clientChainCertificateScript = [][]byte{
 	{
 		0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index 6c40489..0c96a2b 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -98,7 +98,7 @@
 	if !ok {
 		return false, c.sendAlert(alertUnexpectedMessage)
 	}
-	c.vers, ok = mutualVersion(hs.clientHello.vers)
+	c.vers, ok = config.mutualVersion(hs.clientHello.vers)
 	if !ok {
 		return false, c.sendAlert(alertProtocolVersion)
 	}
@@ -203,7 +203,7 @@
 	if hs.sessionState.vers > hs.clientHello.vers {
 		return false
 	}
-	if vers, ok := mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers {
+	if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers {
 		return false
 	}
 
diff --git a/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go
index bf8cbe3..98a57fc 100644
--- a/src/pkg/crypto/tls/handshake_server_test.go
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -48,6 +48,8 @@
 	testConfig.BuildNameToCertificate()
 	testConfig.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
 	testConfig.InsecureSkipVerify = true
+	testConfig.MinVersion = VersionSSL30
+	testConfig.MaxVersion = VersionTLS10
 }
 
 func testClientHelloFailure(t *testing.T, m handshakeMessage, expected error) {
@@ -262,6 +264,13 @@
 	}
 }
 
+func TestTLS11Sesrver(t *testing.T) {
+	var config = *testConfig
+	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
+	config.MaxVersion = VersionTLS11
+	testServerScript(t, "TLS11", tls11ECDHEAESServerScript, &config, nil)
+}
+
 // recordingConn is a net.Conn that records the traffic that passes through it.
 // WriteTo can be used to produce Go code that contains the recorded traffic.
 type recordingConn struct {
@@ -1962,6 +1971,258 @@
 	}},
 }
 
+var tls11ECDHEAESServerScript = [][]byte{
+	{
+		0x16, 0x03, 0x01, 0x01, 0x46, 0x01, 0x00, 0x01,
+		0x42, 0x03, 0x03, 0x51, 0x9f, 0xa3, 0xb0, 0xb7,
+		0x1d, 0x26, 0x93, 0x36, 0xc0, 0x8d, 0x7e, 0xf8,
+		0x4f, 0x6f, 0xc9, 0x3c, 0x31, 0x1e, 0x7f, 0xb1,
+		0xf0, 0xc1, 0x0f, 0xf9, 0x0c, 0xa2, 0xd5, 0xca,
+		0x48, 0xe5, 0x35, 0x00, 0x00, 0xd0, 0xc0, 0x30,
+		0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
+		0xc0, 0x0a, 0xc0, 0x22, 0xc0, 0x21, 0x00, 0xa5,
+		0x00, 0xa3, 0x00, 0xa1, 0x00, 0x9f, 0x00, 0x6b,
+		0x00, 0x6a, 0x00, 0x69, 0x00, 0x68, 0x00, 0x39,
+		0x00, 0x38, 0x00, 0x37, 0x00, 0x36, 0x00, 0x88,
+		0x00, 0x87, 0x00, 0x86, 0x00, 0x85, 0xc0, 0x32,
+		0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
+		0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
+		0x00, 0x84, 0xc0, 0x12, 0xc0, 0x08, 0xc0, 0x1c,
+		0xc0, 0x1b, 0x00, 0x16, 0x00, 0x13, 0x00, 0x10,
+		0x00, 0x0d, 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a,
+		0xc0, 0x2f, 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23,
+		0xc0, 0x13, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x1e,
+		0x00, 0xa4, 0x00, 0xa2, 0x00, 0xa0, 0x00, 0x9e,
+		0x00, 0x67, 0x00, 0x40, 0x00, 0x3f, 0x00, 0x3e,
+		0x00, 0x33, 0x00, 0x32, 0x00, 0x31, 0x00, 0x30,
+		0x00, 0x9a, 0x00, 0x99, 0x00, 0x98, 0x00, 0x97,
+		0x00, 0x45, 0x00, 0x44, 0x00, 0x43, 0x00, 0x42,
+		0xc0, 0x31, 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25,
+		0xc0, 0x0e, 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c,
+		0x00, 0x2f, 0x00, 0x96, 0x00, 0x41, 0x00, 0x07,
+		0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02,
+		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
+		0x00, 0x0f, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x14,
+		0x00, 0x11, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08,
+		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x01, 0x00,
+		0x00, 0x49, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00,
+		0x01, 0x02, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x32,
+		0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0b,
+		0x00, 0x0c, 0x00, 0x18, 0x00, 0x09, 0x00, 0x0a,
+		0x00, 0x16, 0x00, 0x17, 0x00, 0x08, 0x00, 0x06,
+		0x00, 0x07, 0x00, 0x14, 0x00, 0x15, 0x00, 0x04,
+		0x00, 0x05, 0x00, 0x12, 0x00, 0x13, 0x00, 0x01,
+		0x00, 0x02, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x10,
+		0x00, 0x11, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0f,
+		0x00, 0x01, 0x01,
+	},
+	{
+		0x16, 0x03, 0x02, 0x00, 0x30, 0x02, 0x00, 0x00,
+		0x2c, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0xc0, 0x13, 0x00, 0x00,
+		0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x02,
+		0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
+		0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
+		0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
+		0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
+		0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
+		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+		0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
+		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
+		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
+		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
+		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
+		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
+		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
+		0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
+		0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
+		0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
+		0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
+		0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
+		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
+		0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
+		0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
+		0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
+		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+		0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
+		0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
+		0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
+		0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
+		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+		0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
+		0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
+		0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
+		0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
+		0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
+		0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
+		0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
+		0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
+		0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
+		0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
+		0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
+		0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
+		0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
+		0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
+		0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
+		0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
+		0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
+		0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
+		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
+		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+		0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
+		0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
+		0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
+		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+		0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
+		0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
+		0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
+		0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
+		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
+		0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
+		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
+		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
+		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+		0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
+		0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
+		0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
+		0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
+		0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
+		0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
+		0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
+		0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
+		0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
+		0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
+		0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
+		0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
+		0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
+		0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
+		0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
+		0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
+		0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
+		0x16, 0x03, 0x02, 0x01, 0x0f, 0x0c, 0x00, 0x01,
+		0x0b, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
+		0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
+		0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
+		0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
+		0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
+		0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
+		0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
+		0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
+		0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
+		0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
+		0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
+		0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
+		0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
+		0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
+		0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
+		0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
+		0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
+		0x90, 0x33, 0x00, 0x80, 0x16, 0x83, 0x9b, 0xf9,
+		0x72, 0xdb, 0x9f, 0x55, 0x02, 0xe1, 0x04, 0xf7,
+		0xb5, 0x3f, 0x4c, 0x71, 0x13, 0x5a, 0x91, 0xe9,
+		0x1d, 0xeb, 0x9d, 0x9c, 0xfb, 0x88, 0xef, 0xca,
+		0xec, 0x7d, 0x9b, 0xdd, 0xd9, 0xee, 0x2b, 0x8e,
+		0xef, 0xf8, 0xb6, 0xc7, 0x7d, 0xfe, 0xda, 0x7f,
+		0x90, 0x2e, 0x53, 0xf1, 0x64, 0x95, 0xfc, 0x66,
+		0xfc, 0x87, 0x27, 0xb6, 0x9f, 0xc8, 0x3a, 0x95,
+		0x68, 0x17, 0xe1, 0x7d, 0xf1, 0x88, 0xe8, 0x17,
+		0x5f, 0x99, 0x90, 0x3f, 0x47, 0x47, 0x81, 0x06,
+		0xe2, 0x8e, 0x22, 0x56, 0x8f, 0xc2, 0x14, 0xe5,
+		0x62, 0xa7, 0x0d, 0x41, 0x3c, 0xc7, 0x4a, 0x0a,
+		0x74, 0x4b, 0xda, 0x00, 0x8e, 0x4f, 0x90, 0xe6,
+		0xd7, 0x68, 0xe5, 0x8b, 0xf2, 0x3f, 0x53, 0x1d,
+		0x7a, 0xe6, 0xb3, 0xe9, 0x8a, 0xc9, 0x4d, 0x19,
+		0xa6, 0xcf, 0xf9, 0xed, 0x5e, 0x26, 0xdc, 0x90,
+		0x1c, 0x41, 0xad, 0x7c, 0x16, 0x03, 0x02, 0x00,
+		0x04, 0x0e, 0x00, 0x00, 0x00,
+	},
+	{
+		0x16, 0x03, 0x02, 0x00, 0x8a, 0x10, 0x00, 0x00,
+		0x86, 0x85, 0x04, 0x01, 0x11, 0xf2, 0xa4, 0x2d,
+		0x1a, 0x75, 0x6c, 0xbc, 0x2d, 0x91, 0x95, 0x07,
+		0xbe, 0xd6, 0x41, 0x7a, 0xbb, 0xc2, 0x7b, 0xa6,
+		0x9b, 0xe3, 0xdc, 0x41, 0x7f, 0x1e, 0x2e, 0xcc,
+		0x6d, 0xa3, 0x85, 0x53, 0x98, 0x9f, 0x2d, 0xe6,
+		0x3c, 0xb9, 0x82, 0xa6, 0x80, 0x53, 0x9b, 0x71,
+		0xfd, 0x27, 0xe5, 0xe5, 0xdf, 0x13, 0xba, 0x56,
+		0x62, 0x30, 0x4a, 0x57, 0x27, 0xa7, 0xcc, 0x26,
+		0x54, 0xe8, 0x65, 0x6e, 0x4d, 0x00, 0xbf, 0x8a,
+		0xcc, 0x89, 0x6a, 0x6c, 0x88, 0xda, 0x79, 0x4f,
+		0xc5, 0xad, 0x6d, 0x1d, 0x7c, 0x53, 0x7b, 0x1a,
+		0x96, 0xf2, 0xf8, 0x30, 0x01, 0x0b, 0xc2, 0xf0,
+		0x78, 0x41, 0xf4, 0x0d, 0xe0, 0xbe, 0xb9, 0x36,
+		0xe0, 0xb7, 0xee, 0x16, 0xeb, 0x25, 0x67, 0x04,
+		0xc0, 0x2e, 0xd8, 0x34, 0x4a, 0x65, 0xa5, 0xf1,
+		0x95, 0x75, 0xc7, 0x39, 0xa9, 0x68, 0xa9, 0x53,
+		0x93, 0x5b, 0xca, 0x7b, 0x7f, 0xc0, 0x63, 0x14,
+		0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03, 0x02,
+		0x00, 0x40, 0x01, 0xb1, 0xae, 0x1b, 0x8a, 0x65,
+		0xf8, 0x37, 0x50, 0x39, 0x76, 0xef, 0xaa, 0xda,
+		0x84, 0xc9, 0x5f, 0x80, 0xdc, 0xfa, 0xe0, 0x46,
+		0x5a, 0xc7, 0x77, 0x9d, 0x76, 0x03, 0xa6, 0xd5,
+		0x0e, 0xbf, 0x25, 0x30, 0x5c, 0x99, 0x7d, 0xcd,
+		0x2b, 0xaa, 0x2e, 0x8c, 0xdd, 0xda, 0xaa, 0xd7,
+		0xf1, 0xf6, 0x33, 0x47, 0x51, 0x1e, 0x83, 0xa1,
+		0x83, 0x04, 0xd2, 0xb2, 0xc8, 0xbc, 0x11, 0xc5,
+		0x1a, 0x87,
+	},
+	{
+		0x16, 0x03, 0x02, 0x00, 0x72, 0x04, 0x00, 0x00,
+		0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
+		0xeb, 0x8b, 0xc7, 0xef, 0xba, 0xe8, 0x0f, 0x69,
+		0xfe, 0xfb, 0xc3, 0x3d, 0x90, 0x5d, 0xd7, 0xb2,
+		0x51, 0x64, 0xac, 0xc3, 0xae, 0x33, 0x03, 0x42,
+		0x45, 0x2d, 0xa7, 0x57, 0xbd, 0xa3, 0x85, 0x64,
+		0xa6, 0xfe, 0x5c, 0x33, 0x04, 0x93, 0xf2, 0x7c,
+		0x06, 0x6d, 0xd7, 0xd7, 0xcf, 0x4a, 0xaf, 0xb2,
+		0xdd, 0x06, 0xdc, 0x28, 0x14, 0x59, 0x23, 0x02,
+		0xef, 0x97, 0x6a, 0xe8, 0xec, 0xca, 0x10, 0x44,
+		0xcd, 0xb8, 0x50, 0x16, 0x46, 0x5a, 0x05, 0xda,
+		0x04, 0xb3, 0x0e, 0xe9, 0xf0, 0x74, 0xc5, 0x23,
+		0xc2, 0x0e, 0xa1, 0x54, 0x66, 0x7b, 0xe8, 0x14,
+		0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03, 0x02,
+		0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x6b, 0x43, 0x1c, 0x58, 0xbc, 0x85,
+		0xf7, 0xc1, 0x76, 0xbc, 0x72, 0x33, 0x41, 0x6b,
+		0xb8, 0xf8, 0xfd, 0x53, 0x21, 0xc2, 0x41, 0x1b,
+		0x72, 0x4f, 0xce, 0x97, 0xca, 0x14, 0x23, 0x4d,
+		0xbc, 0x44, 0xd6, 0xd7, 0xfc, 0xbc, 0xfd, 0xfd,
+		0x5d, 0x33, 0x42, 0x1b, 0x52, 0x40, 0x0a, 0x2b,
+		0x6c, 0x98, 0x17, 0x03, 0x02, 0x00, 0x40, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d,
+		0x31, 0xef, 0x03, 0x7d, 0xa5, 0x74, 0x92, 0x24,
+		0x34, 0xae, 0x4e, 0xc9, 0xfc, 0x59, 0xcb, 0x64,
+		0xf4, 0x45, 0xb1, 0xac, 0x02, 0xf2, 0x87, 0xe7,
+		0x2f, 0xfd, 0x01, 0xca, 0x78, 0x02, 0x2e, 0x3a,
+		0x38, 0xcd, 0xb1, 0xe0, 0xf2, 0x2e, 0xf6, 0x27,
+		0xa0, 0xac, 0x1f, 0x91, 0x43, 0xc2, 0x3d, 0x15,
+		0x03, 0x02, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x9f, 0x30, 0x24, 0x56,
+		0x2c, 0xde, 0xa0, 0xe6, 0x44, 0x35, 0x30, 0x51,
+		0xec, 0xd4, 0x69, 0x2d, 0x46, 0x64, 0x04, 0x21,
+		0xfe, 0x7c, 0x4d, 0xc5, 0xd0, 0x8c, 0xf9, 0xd2,
+		0x3f, 0x88, 0x69, 0xd5,
+	},
+}
+
 // cert.pem and key.pem were generated with generate_cert.go
 // Thus, they have no ExtKeyUsage fields and trigger an error
 // when verification is turned on.
diff --git a/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go
index b6e73fe..1bf92c8 100644
--- a/src/pkg/crypto/tls/key_agreement.go
+++ b/src/pkg/crypto/tls/key_agreement.go
@@ -36,7 +36,7 @@
 	}
 
 	ciphertext := ckx.ciphertext
-	if version != versionSSL30 {
+	if version != VersionSSL30 {
 		ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
 		if ciphertextLen != len(ckx.ciphertext)-2 {
 			return nil, errors.New("bad ClientKeyExchange")
diff --git a/src/pkg/crypto/tls/prf.go b/src/pkg/crypto/tls/prf.go
index df1eaad..f57b66d 100644
--- a/src/pkg/crypto/tls/prf.go
+++ b/src/pkg/crypto/tls/prf.go
@@ -110,7 +110,7 @@
 // secret. See http://tools.ietf.org/html/rfc5246#section-8.1
 func masterFromPreMasterSecret(version uint16, preMasterSecret, clientRandom, serverRandom []byte) []byte {
 	prf := pRF10
-	if version == versionSSL30 {
+	if version == VersionSSL30 {
 		prf = pRF30
 	}
 
@@ -127,7 +127,7 @@
 // RFC 2246, section 6.3.
 func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
 	prf := pRF10
-	if version == versionSSL30 {
+	if version == VersionSSL30 {
 		prf = pRF30
 	}
 
@@ -224,7 +224,7 @@
 // clientSum returns the contents of the verify_data member of a client's
 // Finished message.
 func (h finishedHash) clientSum(masterSecret []byte) []byte {
-	if h.version == versionSSL30 {
+	if h.version == VersionSSL30 {
 		return finishedSum30(h.clientMD5, h.clientSHA1, masterSecret, ssl3ClientFinishedMagic)
 	}
 
@@ -236,7 +236,7 @@
 // serverSum returns the contents of the verify_data member of a server's
 // Finished message.
 func (h finishedHash) serverSum(masterSecret []byte) []byte {
-	if h.version == versionSSL30 {
+	if h.version == VersionSSL30 {
 		return finishedSum30(h.serverMD5, h.serverSHA1, masterSecret, ssl3ServerFinishedMagic)
 	}
 
diff --git a/src/pkg/crypto/tls/prf_test.go b/src/pkg/crypto/tls/prf_test.go
index 773a2b2..a9b6c9e 100644
--- a/src/pkg/crypto/tls/prf_test.go
+++ b/src/pkg/crypto/tls/prf_test.go
@@ -72,7 +72,7 @@
 // These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
 var testKeysFromTests = []testKeysFromTest{
 	{
-		versionTLS10,
+		VersionTLS10,
 		"0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
 		"4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
 		"4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
@@ -85,7 +85,7 @@
 		16,
 	},
 	{
-		versionTLS10,
+		VersionTLS10,
 		"03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
 		"4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
 		"4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
@@ -98,7 +98,7 @@
 		16,
 	},
 	{
-		versionTLS10,
+		VersionTLS10,
 		"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
 		"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
 		"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
@@ -111,7 +111,7 @@
 		16,
 	},
 	{
-		versionSSL30,
+		VersionSSL30,
 		"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
 		"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
 		"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",