crypto/tls: support CBC ciphers

This is largely based on ality's CL 2747042.

crypto/rc4: API break in order to conform to crypto/cipher's
Stream interface

cipher/cipher: promote to the default build

Since CBC differs between TLS 1.0 and 1.1, we downgrade and
support only 1.0 at the current time. 1.0 is what most of the
world uses.

Given this CL, it would be trival to add support for AES 256,
SHA 256 etc, but I haven't in order to keep the change smaller.

R=rsc
CC=ality, golang-dev
https://golang.org/cl/3659041
diff --git a/src/pkg/Makefile b/src/pkg/Makefile
index aa94cb2..9f449d1 100644
--- a/src/pkg/Makefile
+++ b/src/pkg/Makefile
@@ -32,6 +32,7 @@
 	crypto/block\
 	crypto/blowfish\
 	crypto/cast5\
+	crypto/cipher\
 	crypto/elliptic\
 	crypto/hmac\
 	crypto/md4\
diff --git a/src/pkg/crypto/rc4/rc4.go b/src/pkg/crypto/rc4/rc4.go
index e47a015..65fd195 100644
--- a/src/pkg/crypto/rc4/rc4.go
+++ b/src/pkg/crypto/rc4/rc4.go
@@ -45,14 +45,14 @@
 	return &c, nil
 }
 
-// XORKeyStream will XOR each byte of the given buffer with a byte of the
-// generated keystream.
-func (c *Cipher) XORKeyStream(buf []byte) {
-	for i := range buf {
+// XORKeyStream sets dst to the result of XORing src with the key stream.
+// Dst and src may be the same slice but otherwise should not overlap.
+func (c *Cipher) XORKeyStream(dst, src []byte) {
+	for i := range src {
 		c.i += 1
 		c.j += c.s[c.i]
 		c.s[c.i], c.s[c.j] = c.s[c.j], c.s[c.i]
-		buf[i] ^= c.s[c.s[c.i]+c.s[c.j]]
+		dst[i] = src[i] ^ c.s[c.s[c.i]+c.s[c.j]]
 	}
 }
 
diff --git a/src/pkg/crypto/rc4/rc4_test.go b/src/pkg/crypto/rc4/rc4_test.go
index 73a52e7..6265d94 100644
--- a/src/pkg/crypto/rc4/rc4_test.go
+++ b/src/pkg/crypto/rc4/rc4_test.go
@@ -48,7 +48,7 @@
 			return
 		}
 		keystream := make([]byte, len(g.keystream))
-		c.XORKeyStream(keystream)
+		c.XORKeyStream(keystream, keystream)
 		for j, v := range keystream {
 			if g.keystream[j] != v {
 				t.Errorf("Failed at golden index %d", i)
diff --git a/src/pkg/crypto/tls/Makefile b/src/pkg/crypto/tls/Makefile
index 86f9695..1995a8a 100644
--- a/src/pkg/crypto/tls/Makefile
+++ b/src/pkg/crypto/tls/Makefile
@@ -8,6 +8,7 @@
 GOFILES=\
 	alert.go\
 	ca_set.go\
+	cipher_suites.go\
 	common.go\
 	conn.go\
 	handshake_client.go\
diff --git a/src/pkg/crypto/tls/cipher_suites.go b/src/pkg/crypto/tls/cipher_suites.go
new file mode 100644
index 0000000..c376c58
--- /dev/null
+++ b/src/pkg/crypto/tls/cipher_suites.go
@@ -0,0 +1,62 @@
+// 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.
+
+package tls
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/hmac"
+	"crypto/rc4"
+	"hash"
+)
+
+// A cipherSuite is a specific combination of key agreement, cipher and MAC
+// function. All cipher suites currently assume RSA key agreement.
+type cipherSuite struct {
+	// the lengths, in bytes, of the key material needed for each component.
+	keyLen, macLen, ivLen int
+	cipher                func(key, iv []byte, isRead bool) interface{}
+	mac                   func(macKey []byte) hash.Hash
+}
+
+var cipherSuites = map[uint16]*cipherSuite{
+	TLS_RSA_WITH_RC4_128_SHA:     &cipherSuite{16, 20, 0, cipherRC4, hmacSHA1},
+	TLS_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, cipherAES, hmacSHA1},
+}
+
+func cipherRC4(key, iv []byte, isRead bool) interface{} {
+	cipher, _ := rc4.NewCipher(key)
+	return cipher
+}
+
+func cipherAES(key, iv []byte, isRead bool) interface{} {
+	block, _ := aes.NewCipher(key)
+	if isRead {
+		return cipher.NewCBCDecrypter(block, iv)
+	}
+	return cipher.NewCBCEncrypter(block, iv)
+}
+
+func hmacSHA1(key []byte) hash.Hash {
+	return hmac.NewSHA1(key)
+}
+
+// mutualCipherSuite returns a cipherSuite and its id given a list of supported
+// ciphersuites and the id requested by the peer.
+func mutualCipherSuite(have []uint16, want uint16) (suite *cipherSuite, id uint16) {
+	for _, id := range have {
+		if want == id {
+			return cipherSuites[id], id
+		}
+	}
+	return
+}
+
+// A list of the possible cipher suite ids. Taken from
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+const (
+	TLS_RSA_WITH_RC4_128_SHA     uint16 = 0x0005
+	TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
+)
diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go
index 4fb17ad..1cb2d85 100644
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -20,7 +20,7 @@
 	maxHandshake    = 65536        // maximum handshake we support (protocol max is 16 MB)
 
 	minVersion = 0x0301 // minimum supported version - TLS 1.0
-	maxVersion = 0x0302 // maximum supported version - TLS 1.1
+	maxVersion = 0x0301 // maximum supported version - TLS 1.0
 )
 
 // TLS record types.
@@ -47,11 +47,6 @@
 	typeNextProtocol       uint8 = 67 // Not IANA assigned
 )
 
-// TLS cipher suites.
-const (
-	TLS_RSA_WITH_RC4_128_SHA uint16 = 5
-)
-
 // TLS compression types.
 const (
 	compressionNone uint8 = 0
@@ -120,6 +115,10 @@
 	// certificate nor does it require that the certificate sent be
 	// anything more than self-signed.
 	AuthenticateClient bool
+
+	// CipherSuites is a list of supported cipher suites. If CipherSuites
+	// is nil, TLS uses a list of suites supported by the implementation.
+	CipherSuites []uint16
 }
 
 func (c *Config) rand() io.Reader {
@@ -146,6 +145,14 @@
 	return s
 }
 
+func (c *Config) cipherSuites() []uint16 {
+	s := c.CipherSuites
+	if len(s) == 0 {
+		s = defaultCipherSuites()
+	}
+	return s
+}
+
 // A Certificate is a chain of one or more certificates, leaf first.
 type Certificate struct {
 	Certificate [][]byte
@@ -164,11 +171,6 @@
 	unmarshal([]byte) bool
 }
 
-type encryptor interface {
-	// XORKeyStream xors the contents of the slice with bytes from the key stream.
-	XORKeyStream(buf []byte)
-}
-
 // mutualVersion returns the protocol version to use given the advertised
 // version of the peer.
 func mutualVersion(vers uint16) (uint16, bool) {
@@ -199,10 +201,20 @@
 var once sync.Once
 
 func defaultRoots() *CASet {
-	once.Do(initDefaultRoots)
+	once.Do(initDefaults)
 	return varDefaultRoots
 }
 
+func defaultCipherSuites() []uint16 {
+	once.Do(initDefaults)
+	return varDefaultCipherSuites
+}
+
+func initDefaults() {
+	initDefaultRoots()
+	initDefaultCipherSuites()
+}
+
 var varDefaultRoots *CASet
 
 func initDefaultRoots() {
@@ -216,3 +228,14 @@
 	}
 	varDefaultRoots = roots
 }
+
+var varDefaultCipherSuites []uint16
+
+func initDefaultCipherSuites() {
+	varDefaultCipherSuites = make([]uint16, len(cipherSuites))
+	i := 0
+	for id, _ := range cipherSuites {
+		varDefaultCipherSuites[i] = id
+		i++
+	}
+}
diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go
index 125d0a9..8b1cd86 100644
--- a/src/pkg/crypto/tls/conn.go
+++ b/src/pkg/crypto/tls/conn.go
@@ -1,9 +1,14 @@
+// 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 layer
 
 package tls
 
 import (
 	"bytes"
+	"crypto/cipher"
 	"crypto/subtle"
 	"crypto/x509"
 	"hash"
@@ -99,31 +104,31 @@
 // connection, either sending or receiving.
 type halfConn struct {
 	sync.Mutex
-	crypt encryptor // encryption state
-	mac   hash.Hash // MAC algorithm
-	seq   [8]byte   // 64-bit sequence number
-	bfree *block    // list of free blocks
+	cipher interface{} // cipher algorithm
+	mac    hash.Hash   // MAC algorithm
+	seq    [8]byte     // 64-bit sequence number
+	bfree  *block      // list of free blocks
 
-	nextCrypt encryptor // next encryption state
-	nextMac   hash.Hash // next MAC algorithm
+	nextCipher interface{} // next encryption state
+	nextMac    hash.Hash   // next MAC algorithm
 }
 
 // prepareCipherSpec sets the encryption and MAC states
 // that a subsequent changeCipherSpec will use.
-func (hc *halfConn) prepareCipherSpec(crypt encryptor, mac hash.Hash) {
-	hc.nextCrypt = crypt
+func (hc *halfConn) prepareCipherSpec(cipher interface{}, mac hash.Hash) {
+	hc.nextCipher = cipher
 	hc.nextMac = mac
 }
 
 // changeCipherSpec changes the encryption and MAC states
 // to the ones previously passed to prepareCipherSpec.
 func (hc *halfConn) changeCipherSpec() os.Error {
-	if hc.nextCrypt == nil {
+	if hc.nextCipher == nil {
 		return alertInternalError
 	}
-	hc.crypt = hc.nextCrypt
+	hc.cipher = hc.nextCipher
 	hc.mac = hc.nextMac
-	hc.nextCrypt = nil
+	hc.nextCipher = nil
 	hc.nextMac = nil
 	return nil
 }
@@ -150,27 +155,102 @@
 	}
 }
 
+// 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.2
+func 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 zero
+	good := 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 here
+	if 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 zero
+		mask := 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 << 4
+	good &= good << 2
+	good &= good << 1
+	good = uint8(int8(good) >> 7)
+
+	toRemove := good&paddingLen + 1
+	return payload[:len(payload)-int(toRemove)], good
+}
+
+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 payload
 	payload := b.data[recordHeaderLen:]
 
+	macSize := 0
+	if hc.mac != nil {
+		macSize = hc.mac.Size()
+	}
+
+	paddingGood := byte(255)
+
 	// decrypt
-	if hc.crypt != nil {
-		hc.crypt.XORKeyStream(payload)
+	if 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)
+			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 behaviour matches OpenSSL, so we leak
+			// only as much as they do.
+		default:
+			panic("unknown cipher type")
+		}
 	}
 
 	// check, strip mac
 	if hc.mac != nil {
-		if len(payload) < hc.mac.Size() {
+		if len(payload) < macSize {
 			return false, alertBadRecordMAC
 		}
 
 		// strip mac off payload, b.data
-		n := len(payload) - hc.mac.Size()
+		n := len(payload) - macSize
 		b.data[3] = byte(n >> 8)
 		b.data[4] = byte(n)
-		b.data = b.data[0 : recordHeaderLen+n]
+		b.resize(recordHeaderLen + n)
 		remoteMAC := payload[n:]
 
 		hc.mac.Reset()
@@ -178,7 +258,7 @@
 		hc.incSeq()
 		hc.mac.Write(b.data)
 
-		if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 {
+		if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 || paddingGood != 255 {
 			return false, alertBadRecordMAC
 		}
 	}
@@ -186,6 +266,23 @@
 	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) % blockSize
+	paddingLen := blockSize - overrun
+	prefix = 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) {
 	// mac
@@ -198,18 +295,30 @@
 		n := len(b.data)
 		b.resize(n + len(mac))
 		copy(b.data[n:], mac)
-
-		// update length to include mac
-		n = len(b.data) - recordHeaderLen
-		b.data[3] = byte(n >> 8)
-		b.data[4] = byte(n)
 	}
 
+	payload := b.data[recordHeaderLen:]
+
 	// encrypt
-	if hc.crypt != nil {
-		hc.crypt.XORKeyStream(b.data[recordHeaderLen:])
+	if 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) - recordHeaderLen
+	b.data[3] = byte(n >> 8)
+	b.data[4] = byte(n)
+
 	return true, 0
 }
 
diff --git a/src/pkg/crypto/tls/conn_test.go b/src/pkg/crypto/tls/conn_test.go
new file mode 100644
index 0000000..ee654ca
--- /dev/null
+++ b/src/pkg/crypto/tls/conn_test.go
@@ -0,0 +1,52 @@
+// 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.
+
+package tls
+
+import (
+	"testing"
+)
+
+func TestRoundUp(t *testing.T) {
+	if roundUp(0, 16) != 0 ||
+		roundUp(1, 16) != 16 ||
+		roundUp(15, 16) != 16 ||
+		roundUp(16, 16) != 16 ||
+		roundUp(17, 16) != 32 {
+		t.Error("roundUp broken")
+	}
+}
+
+var paddingTests = []struct {
+	in          []byte
+	good        bool
+	expectedLen int
+}{
+	{[]byte{1, 2, 3, 4, 0}, true, 4},
+	{[]byte{1, 2, 3, 4, 0, 1}, false, 0},
+	{[]byte{1, 2, 3, 4, 99, 99}, false, 0},
+	{[]byte{1, 2, 3, 4, 1, 1}, true, 4},
+	{[]byte{1, 2, 3, 2, 2, 2}, true, 3},
+	{[]byte{1, 2, 3, 3, 3, 3}, true, 2},
+	{[]byte{1, 2, 3, 4, 3, 3}, false, 0},
+	{[]byte{1, 4, 4, 4, 4, 4}, true, 1},
+	{[]byte{5, 5, 5, 5, 5, 5}, true, 0},
+	{[]byte{6, 6, 6, 6, 6, 6}, false, 0},
+}
+
+func TestRemovePadding(t *testing.T) {
+	for i, test := range paddingTests {
+		payload, good := removePadding(test.in)
+		expectedGood := byte(255)
+		if !test.good {
+			expectedGood = 0
+		}
+		if good != expectedGood {
+			t.Errorf("#%d: wrong validity, want:%d got:%d", expectedGood, good)
+		}
+		if good == 255 && len(payload) != test.expectedLen {
+			t.Errorf("#%d: got %d, want %d", i, len(payload), test.expectedLen)
+		}
+	}
+}
diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go
index 4cddba3..e5e8a1f 100644
--- a/src/pkg/crypto/tls/handshake_client.go
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -5,8 +5,6 @@
 package tls
 
 import (
-	"crypto/hmac"
-	"crypto/rc4"
 	"crypto/rsa"
 	"crypto/subtle"
 	"crypto/x509"
@@ -23,7 +21,7 @@
 
 	hello := &clientHelloMsg{
 		vers:               maxVersion,
-		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+		cipherSuites:       c.config.cipherSuites(),
 		compressionMethods: []uint8{compressionNone},
 		random:             make([]byte, 32),
 		ocspStapling:       true,
@@ -61,11 +59,15 @@
 	c.vers = vers
 	c.haveVers = true
 
-	if serverHello.cipherSuite != TLS_RSA_WITH_RC4_128_SHA ||
-		serverHello.compressionMethod != compressionNone {
+	if serverHello.compressionMethod != compressionNone {
 		return c.sendAlert(alertUnexpectedMessage)
 	}
 
+	suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
+	if suite == nil {
+		return c.sendAlert(alertHandshakeFailure)
+	}
+
 	msg, err = c.readHandshake()
 	if err != nil {
 		return err
@@ -245,13 +247,12 @@
 		c.writeRecord(recordTypeHandshake, certVerify.marshal())
 	}
 
-	suite := cipherSuites[0]
-	masterSecret, clientMAC, serverMAC, clientKey, serverKey :=
-		keysFromPreMasterSecret11(preMasterSecret, hello.random, serverHello.random, suite.hashLength, suite.cipherKeyLength)
+	masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+		keysFromPreMasterSecret10(preMasterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
 
-	cipher, _ := rc4.NewCipher(clientKey)
-
-	c.out.prepareCipherSpec(cipher, hmac.NewSHA1(clientMAC))
+	clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */ )
+	clientHash := suite.mac(clientMAC)
+	c.out.prepareCipherSpec(clientCipher, clientHash)
 	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
 
 	finished := new(finishedMsg)
@@ -259,8 +260,9 @@
 	finishedHash.Write(finished.marshal())
 	c.writeRecord(recordTypeHandshake, finished.marshal())
 
-	cipher2, _ := rc4.NewCipher(serverKey)
-	c.in.prepareCipherSpec(cipher2, hmac.NewSHA1(serverMAC))
+	serverCipher := suite.cipher(serverKey, serverIV, true /* for reading */ )
+	serverHash := suite.mac(serverMAC)
+	c.in.prepareCipherSpec(serverCipher, serverHash)
 	c.readRecord(recordTypeChangeCipherSpec)
 	if c.err != nil {
 		return c.err
@@ -282,6 +284,6 @@
 	}
 
 	c.handshakeComplete = true
-	c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA
+	c.cipherSuite = suiteId
 	return nil
 }
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index 6db2a6a..29c8aad 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -4,17 +4,7 @@
 
 package tls
 
-// The handshake goroutine reads handshake messages from the record processor
-// and outputs messages to be written on another channel. It updates the record
-// processor with the state of the connection via the control channel. In the
-// case of handshake messages that need synchronous processing (because they
-// affect the handling of the next record) the record processor knows about
-// them and either waits for a control message (Finished) or includes a reply
-// channel in the message (ChangeCipherSpec).
-
 import (
-	"crypto/hmac"
-	"crypto/rc4"
 	"crypto/rsa"
 	"crypto/subtle"
 	"crypto/x509"
@@ -22,16 +12,6 @@
 	"os"
 )
 
-type cipherSuite struct {
-	id                          uint16 // The number of this suite on the wire.
-	hashLength, cipherKeyLength int
-	// TODO(agl): need a method to create the cipher and hash interfaces.
-}
-
-var cipherSuites = []cipherSuite{
-	{TLS_RSA_WITH_RC4_128_SHA, 20, 16},
-}
-
 func (c *Conn) serverHandshake() os.Error {
 	config := c.config
 	msg, err := c.readHandshake()
@@ -54,16 +34,13 @@
 
 	hello := new(serverHelloMsg)
 
-	// We only support a single ciphersuite so we look for it in the list
-	// of client supported suites.
-	//
-	// TODO(agl): Add additional cipher suites.
 	var suite *cipherSuite
-
+	var suiteId uint16
 	for _, id := range clientHello.cipherSuites {
-		for _, supported := range cipherSuites {
-			if supported.id == id {
-				suite = &supported
+		for _, supported := range config.cipherSuites() {
+			if id == supported {
+				suite = cipherSuites[id]
+				suiteId = id
 				break
 			}
 		}
@@ -83,7 +60,7 @@
 	}
 
 	hello.vers = vers
-	hello.cipherSuite = suite.id
+	hello.cipherSuite = suiteId
 	t := uint32(config.time())
 	hello.random = make([]byte, 32)
 	hello.random[0] = byte(t >> 24)
@@ -225,11 +202,12 @@
 	// wrong version anyway. See the discussion at the end of section
 	// 7.4.7.1 of RFC 4346.
 
-	masterSecret, clientMAC, serverMAC, clientKey, serverKey :=
-		keysFromPreMasterSecret11(preMasterSecret, clientHello.random, hello.random, suite.hashLength, suite.cipherKeyLength)
+	masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+		keysFromPreMasterSecret10(preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)
 
-	cipher, _ := rc4.NewCipher(clientKey)
-	c.in.prepareCipherSpec(cipher, hmac.NewSHA1(clientMAC))
+	clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */ )
+	clientHash := suite.mac(clientMAC)
+	c.in.prepareCipherSpec(clientCipher, clientHash)
 	c.readRecord(recordTypeChangeCipherSpec)
 	if err := c.error(); err != nil {
 		return err
@@ -265,8 +243,9 @@
 
 	finishedHash.Write(clientFinished.marshal())
 
-	cipher2, _ := rc4.NewCipher(serverKey)
-	c.out.prepareCipherSpec(cipher2, hmac.NewSHA1(serverMAC))
+	serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */ )
+	serverHash := suite.mac(serverMAC)
+	c.out.prepareCipherSpec(serverCipher, serverHash)
 	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
 
 	finished := new(finishedMsg)
@@ -274,7 +253,7 @@
 	c.writeRecord(recordTypeHandshake, finished.marshal())
 
 	c.handshakeComplete = true
-	c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA
+	c.cipherSuite = suiteId
 
 	return nil
 }
diff --git a/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go
index efdbb66..ad82e39 100644
--- a/src/pkg/crypto/tls/handshake_server_test.go
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -5,8 +5,8 @@
 package tls
 
 import (
-	//	"bytes"
 	"big"
+	"bytes"
 	"crypto/rsa"
 	"encoding/hex"
 	"flag"
@@ -14,7 +14,6 @@
 	"net"
 	"os"
 	"testing"
-	//	"testing/script"
 )
 
 type zeroSource struct{}
@@ -36,6 +35,7 @@
 	testConfig.Certificates = make([]Certificate, 1)
 	testConfig.Certificates[0].Certificate = [][]byte{testCertificate}
 	testConfig.Certificates[0].PrivateKey = testPrivateKey
+	testConfig.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
 }
 
 func testClientHelloFailure(t *testing.T, m handshakeMessage, expected os.Error) {
@@ -107,9 +107,9 @@
 }
 
 
-func TestHandshakeServer(t *testing.T) {
+func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config) {
 	c, s := net.Pipe()
-	srv := Server(s, testConfig)
+	srv := Server(s, config)
 	go func() {
 		srv.Write([]byte("hello, world\n"))
 		srv.Close()
@@ -124,15 +124,23 @@
 		bb := make([]byte, len(b))
 		_, err := io.ReadFull(c, bb)
 		if err != nil {
-			t.Fatalf("#%d: %s", i, err)
+			t.Fatalf("%s #%d: %s", name, i, err)
+		}
+		if !bytes.Equal(b, bb) {
+			t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
 		}
 	}
+}
 
-	if !srv.haveVers || srv.vers != 0x0302 {
-		t.Errorf("server version incorrect: %v %v", srv.haveVers, srv.vers)
-	}
+func TestHandshakeServerRC4(t *testing.T) {
+	testServerScript(t, "RC4", rc4ServerScript, testConfig)
+}
 
-	// TODO: check protocol
+func TestHandshakeServerAES(t *testing.T) {
+	aesConfig := new(Config)
+	*aesConfig = *testConfig
+	aesConfig.CipherSuites = []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}
+	testServerScript(t, "AES", aesServerScript, aesConfig)
 }
 
 var serve = flag.Bool("serve", false, "run a TLS server on :10443")
@@ -185,109 +193,319 @@
 // and then running 6.out -serve to start a server and then
 // gnutls-cli --insecure --debug 100 -p 10443 localhost
 // to dump a session.
-var serverScript = [][]byte{
-	// Alternate write and read.
+var rc4ServerScript = [][]byte{
 	{
-		0x16, 0x03, 0x02, 0x00, 0x71, 0x01, 0x00, 0x00, 0x6d, 0x03, 0x02, 0x4b, 0xd4, 0xee, 0x6e, 0xab,
-		0x0b, 0xc3, 0x01, 0xd6, 0x8d, 0xe0, 0x72, 0x7e, 0x6c, 0x04, 0xbe, 0x9a, 0x3c, 0xa3, 0xd8, 0x95,
-		0x28, 0x00, 0xb2, 0xe8, 0x1f, 0xdd, 0xb0, 0xec, 0xca, 0x46, 0x1f, 0x00, 0x00, 0x28, 0x00, 0x33,
-		0x00, 0x39, 0x00, 0x16, 0x00, 0x32, 0x00, 0x38, 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
-		0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x00, 0x8c,
-		0x00, 0x8d, 0x00, 0x8b, 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1c, 0x00, 0x09, 0x00, 0x03, 0x02, 0x00,
-		0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0f, 0x00, 0x00, 0x0c, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36,
-		0x38, 0x2e, 0x30, 0x2e, 0x31, 0x30,
+		0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00,
+		0x7b, 0x03, 0x02, 0x4d, 0x08, 0x1f, 0x5a, 0x7a,
+		0x0a, 0x92, 0x2f, 0xf0, 0x73, 0x16, 0x3a, 0x88,
+		0x14, 0x85, 0x4c, 0x98, 0x15, 0x7b, 0x65, 0xe0,
+		0x78, 0xd0, 0xed, 0xd0, 0xf3, 0x65, 0x20, 0xeb,
+		0x80, 0xd1, 0x0b, 0x00, 0x00, 0x34, 0x00, 0x33,
+		0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+		0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+		0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+		0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+		0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+		0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+		0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09,
+		0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+		0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+		0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff,
+		0x01, 0x00, 0x01, 0x00,
 	},
 
 	{
-		0x16, 0x03, 0x02, 0x00, 0x2a,
-		0x02, 0x00, 0x00, 0x26, 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, 0x05, 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, 0x00, 0x04,
-		0x0e, 0x00, 0x00, 0x00,
+		0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+		0x26, 0x03, 0x01, 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, 0x05, 0x00, 0x16,
+		0x03, 0x01, 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, 0x01, 0x00, 0x04, 0x0e,
+		0x00, 0x00, 0x00,
 	},
 
 	{
-		0x16, 0x03, 0x02, 0x00, 0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0x3b, 0x7a, 0x9b, 0x05, 0xfd,
-		0x1b, 0x0d, 0x81, 0xf0, 0xac, 0x59, 0x57, 0x4e, 0xb6, 0xf5, 0x81, 0xed, 0x52, 0x78, 0xc5, 0xff,
-		0x36, 0x33, 0x9c, 0x94, 0x31, 0xc3, 0x14, 0x98, 0x5d, 0xa0, 0x49, 0x23, 0x11, 0x67, 0xdf, 0x73,
-		0x1b, 0x81, 0x0b, 0xdd, 0x10, 0xda, 0xee, 0xb5, 0x68, 0x61, 0xa9, 0xb6, 0x15, 0xae, 0x1a, 0x11,
-		0x31, 0x42, 0x2e, 0xde, 0x01, 0x4b, 0x81, 0x70, 0x03, 0xc8, 0x5b, 0xca, 0x21, 0x88, 0x25, 0xef,
-		0x89, 0xf0, 0xb7, 0xff, 0x24, 0x32, 0xd3, 0x14, 0x76, 0xe2, 0x50, 0x5c, 0x2e, 0x75, 0x9d, 0x5c,
-		0xa9, 0x80, 0x3d, 0x6f, 0xd5, 0x46, 0xd3, 0xdb, 0x42, 0x6e, 0x55, 0x81, 0x88, 0x42, 0x0e, 0x45,
-		0xfe, 0x9e, 0xe4, 0x41, 0x79, 0xcf, 0x71, 0x0e, 0xed, 0x27, 0xa8, 0x20, 0x05, 0xe9, 0x7a, 0x42,
-		0x4f, 0x05, 0x10, 0x2e, 0x52, 0x5d, 0x8c, 0x3c, 0x40, 0x49, 0x4c,
-
-		0x14, 0x03, 0x02, 0x00, 0x01, 0x01,
-
-		0x16, 0x03, 0x02, 0x00, 0x24, 0x8b, 0x12, 0x24, 0x06, 0xaa, 0x92, 0x74, 0xa1, 0x46, 0x6f, 0xc1,
-		0x4e, 0x4a, 0xf7, 0x16, 0xdd, 0xd6, 0xe1, 0x2d, 0x37, 0x0b, 0x44, 0xba, 0xeb, 0xc4, 0x6c, 0xc7,
-		0xa0, 0xb7, 0x8c, 0x9d, 0x24, 0xbd, 0x99, 0x33, 0x1e,
+		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
+		0x82, 0x00, 0x80, 0x3c, 0x13, 0xd7, 0x12, 0xc1,
+		0x6a, 0xf0, 0x3f, 0x8c, 0xa1, 0x35, 0x5d, 0xc5,
+		0x89, 0x1e, 0x9e, 0xcd, 0x32, 0xc7, 0x9e, 0xe6,
+		0xae, 0xd5, 0xf1, 0xbf, 0x70, 0xd7, 0xa9, 0xef,
+		0x2c, 0x4c, 0xf4, 0x22, 0xbc, 0x17, 0x17, 0xaa,
+		0x05, 0xf3, 0x9f, 0x80, 0xf2, 0xe9, 0x82, 0x2f,
+		0x2a, 0x15, 0x54, 0x0d, 0x16, 0x0e, 0x77, 0x4c,
+		0x28, 0x3c, 0x03, 0x2d, 0x2d, 0xd7, 0xc8, 0x64,
+		0xd9, 0x59, 0x4b, 0x1c, 0xf4, 0xde, 0xff, 0x2f,
+		0xbc, 0x94, 0xaf, 0x18, 0x26, 0x37, 0xce, 0x4f,
+		0x84, 0x74, 0x2e, 0x45, 0x66, 0x7c, 0x0c, 0x54,
+		0x46, 0x36, 0x5f, 0x65, 0x21, 0x7b, 0x83, 0x8c,
+		0x6d, 0x76, 0xcd, 0x0d, 0x9f, 0xda, 0x1c, 0xa4,
+		0x6e, 0xfe, 0xb1, 0xf7, 0x09, 0x0d, 0xfb, 0x74,
+		0x66, 0x34, 0x99, 0x89, 0x7f, 0x5f, 0x77, 0x87,
+		0x4a, 0x66, 0x4b, 0xa9, 0x59, 0x57, 0xe3, 0x56,
+		0x0d, 0xdd, 0xd8, 0x14, 0x03, 0x01, 0x00, 0x01,
+		0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc0, 0x4e,
+		0xd3, 0x0f, 0xb5, 0xc0, 0x57, 0xa6, 0x18, 0x80,
+		0x80, 0x6b, 0x49, 0xfe, 0xbd, 0x3a, 0x7a, 0x2c,
+		0xef, 0x70, 0xb5, 0x1c, 0xd2, 0xdf, 0x5f, 0x78,
+		0x5a, 0xd8, 0x4f, 0xa0, 0x95, 0xb4, 0xb3, 0xb5,
+		0xaa, 0x3b,
 	},
 
 	{
-		0x14, 0x03, 0x02, 0x00, 0x01,
-		0x01,
+		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+		0x01, 0x00, 0x24, 0x9d, 0xc9, 0xda, 0xdf, 0xeb,
+		0xc8, 0xdb, 0xf8, 0x94, 0xa5, 0xef, 0xd5, 0xfc,
+		0x89, 0x01, 0x64, 0x30, 0x77, 0x5a, 0x18, 0x4b,
+		0x16, 0x79, 0x9c, 0xf6, 0xf5, 0x09, 0x22, 0x12,
+		0x4c, 0x3e, 0xa8, 0x8e, 0x91, 0xa5, 0x24,
+	},
+}
 
-		0x16, 0x03, 0x02, 0x00, 0x24,
-		0x6e, 0xd1, 0x3e, 0x49, 0x68, 0xc1, 0xa0, 0xa5, 0xb7, 0xaf, 0xb0, 0x7c, 0x52, 0x1f, 0xf7, 0x2d,
-		0x51, 0xf3, 0xa5, 0xb6, 0xf6, 0xd4, 0x18, 0x4b, 0x7a, 0xd5, 0x24, 0x1d, 0x09, 0xb6, 0x41, 0x1c,
-		0x1c, 0x98, 0xf6, 0x90,
+var aesServerScript = [][]byte{
+	{
+		0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00,
+		0x7b, 0x03, 0x02, 0x4d, 0x08, 0x2d, 0x0b, 0xb3,
+		0x57, 0x85, 0x71, 0x4b, 0xfb, 0x34, 0xab, 0x16,
+		0xd4, 0x92, 0x50, 0x81, 0x16, 0x95, 0x11, 0x28,
+		0x1a, 0xcb, 0xff, 0x09, 0x4d, 0x23, 0xa6, 0xfe,
+		0x2e, 0xbb, 0x78, 0x00, 0x00, 0x34, 0x00, 0x33,
+		0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+		0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+		0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+		0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+		0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+		0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+		0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09,
+		0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+		0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+		0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff,
+		0x01, 0x00, 0x01, 0x00,
+	},
 
-		0x17, 0x03, 0x02, 0x00, 0x21,
-		0x50, 0xb7, 0x92, 0x4f, 0xd8, 0x78, 0x29, 0xa2, 0xe7, 0xa5, 0xa6, 0xbd, 0x1a, 0x0c, 0xf1, 0x5a,
-		0x6e, 0x6c, 0xeb, 0x38, 0x99, 0x9b, 0x3c, 0xfd, 0xee, 0x53, 0xe8, 0x4d, 0x7b, 0xa5, 0x5b, 0x00,
+	{
+		0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+		0x26, 0x03, 0x01, 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, 0x2f, 0x00, 0x16,
+		0x03, 0x01, 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, 0x01, 0x00, 0x04, 0x0e,
+		0x00, 0x00, 0x00,
+	},
 
-		0xb9,
+	{
+		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
+		0x82, 0x00, 0x80, 0x71, 0x9c, 0xe7, 0x23, 0xfc,
+		0xb9, 0x19, 0x29, 0x82, 0xbf, 0xef, 0x08, 0xf7,
+		0x99, 0x36, 0xc3, 0x4c, 0x6f, 0x05, 0xd2, 0x8b,
+		0x62, 0x2b, 0x19, 0x9b, 0x7f, 0xc0, 0xcc, 0x48,
+		0x30, 0x5f, 0xcd, 0xc3, 0x70, 0x55, 0x53, 0x73,
+		0xfa, 0x79, 0x74, 0xf3, 0xa3, 0x76, 0x9f, 0xa1,
+		0x7f, 0x98, 0xc2, 0xc0, 0xe3, 0xc5, 0xa0, 0x31,
+		0x2f, 0xa6, 0xe8, 0x1e, 0x61, 0x46, 0xb3, 0x9b,
+		0x4b, 0x16, 0xf1, 0x2d, 0xc7, 0x63, 0x7f, 0x79,
+		0x22, 0x30, 0xd1, 0xf2, 0xfc, 0x77, 0x98, 0x0a,
+		0x16, 0x11, 0x63, 0x71, 0x7f, 0x70, 0xef, 0x16,
+		0xbb, 0x39, 0x87, 0x34, 0xac, 0x49, 0xbd, 0x07,
+		0x67, 0xcb, 0x9c, 0xcc, 0xde, 0xef, 0xb1, 0xe0,
+		0xdb, 0x01, 0xb5, 0x35, 0xa9, 0xb3, 0x10, 0x0c,
+		0x4b, 0xee, 0xb3, 0x4e, 0xfd, 0xbe, 0x15, 0x27,
+		0xf0, 0x46, 0xb2, 0x38, 0xba, 0x5f, 0xcc, 0x89,
+		0xec, 0x29, 0x82, 0x14, 0x03, 0x01, 0x00, 0x01,
+		0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x3c, 0xfb,
+		0xa4, 0x12, 0xcb, 0x00, 0xf9, 0x57, 0x7e, 0x9b,
+		0xc9, 0xdc, 0x0c, 0xba, 0x9a, 0x81, 0x62, 0xfb,
+		0x26, 0x13, 0x53, 0xfe, 0xaa, 0xcc, 0x82, 0xbb,
+		0xb6, 0x67, 0x7f, 0x39, 0xbe, 0x4d, 0xbb, 0xc0,
+		0x6c, 0x24, 0x31, 0x83, 0xa5, 0x50, 0x3a, 0x75,
+		0x32, 0x64, 0xb5, 0xdb, 0xbe, 0x0a,
+	},
 
-		0x15, 0x03, 0x02, 0x00, 0x16,
-		0xc7, 0xc9, 0x5a, 0x72, 0xfb, 0x02, 0xa5, 0x93, 0xdd, 0x69, 0xeb, 0x30, 0x68, 0x5e, 0xbc, 0xe0,
-		0x44, 0xb9, 0x59, 0x33, 0x68, 0xa9,
+	{
+		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+		0x01, 0x00, 0x30, 0x43, 0x24, 0x42, 0x55, 0x08,
+		0xe4, 0xc2, 0x15, 0xc9, 0xdb, 0x71, 0x69, 0xee,
+		0x09, 0xc5, 0x1c, 0xfd, 0x46, 0x10, 0xa0, 0x68,
+		0x21, 0xf2, 0x48, 0xac, 0x6c, 0xc0, 0x2b, 0x62,
+		0x07, 0x8f, 0x48, 0x33, 0x0a, 0x6b, 0x62, 0x28,
+		0x2e, 0x2c, 0xad, 0xcb, 0x34, 0x85, 0xca, 0x2e,
+		0xcd, 0x84, 0xf0,
 	},
 }
diff --git a/src/pkg/crypto/tls/prf.go b/src/pkg/crypto/tls/prf.go
index b206d26..478cf65 100644
--- a/src/pkg/crypto/tls/prf.go
+++ b/src/pkg/crypto/tls/prf.go
@@ -44,8 +44,8 @@
 	}
 }
 
-// pRF11 implements the TLS 1.1 pseudo-random function, as defined in RFC 4346, section 5.
-func pRF11(result, secret, label, seed []byte) {
+// pRF10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
+func pRF10(result, secret, label, seed []byte) {
 	hashSHA1 := sha1.New
 	hashMD5 := md5.New
 
@@ -75,25 +75,32 @@
 var serverFinishedLabel = []byte("server finished")
 
 // keysFromPreMasterSecret generates the connection keys from the pre master
-// secret, given the lengths of the MAC and cipher keys, as defined in RFC
-// 4346, section 6.3.
-func keysFromPreMasterSecret11(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey []byte) {
+// secret, given the lengths of the MAC key, cipher key and IV, as defined in
+// RFC 2246, section 6.3.
+func keysFromPreMasterSecret10(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
 	var seed [tlsRandomLength * 2]byte
 	copy(seed[0:len(clientRandom)], clientRandom)
 	copy(seed[len(clientRandom):], serverRandom)
 	masterSecret = make([]byte, masterSecretLength)
-	pRF11(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+	pRF10(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
 
 	copy(seed[0:len(clientRandom)], serverRandom)
 	copy(seed[len(serverRandom):], clientRandom)
 
-	n := 2*macLen + 2*keyLen
+	n := 2*macLen + 2*keyLen + 2*ivLen
 	keyMaterial := make([]byte, n)
-	pRF11(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
-	clientMAC = keyMaterial[0:macLen]
-	serverMAC = keyMaterial[macLen : macLen*2]
-	clientKey = keyMaterial[macLen*2 : macLen*2+keyLen]
-	serverKey = keyMaterial[macLen*2+keyLen:]
+	pRF10(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+	clientMAC = keyMaterial[:macLen]
+	keyMaterial = keyMaterial[macLen:]
+	serverMAC = keyMaterial[:macLen]
+	keyMaterial = keyMaterial[macLen:]
+	clientKey = keyMaterial[:keyLen]
+	keyMaterial = keyMaterial[keyLen:]
+	serverKey = keyMaterial[:keyLen]
+	keyMaterial = keyMaterial[keyLen:]
+	clientIV = keyMaterial[:ivLen]
+	keyMaterial = keyMaterial[ivLen:]
+	serverIV = keyMaterial[:ivLen]
 	return
 }
 
@@ -125,7 +132,7 @@
 	copy(seed, md5)
 	copy(seed[len(md5):], sha1)
 	out := make([]byte, finishedVerifyLength)
-	pRF11(out, masterSecret, label, seed)
+	pRF10(out, masterSecret, label, seed)
 	return out
 }
 
diff --git a/src/pkg/crypto/tls/prf_test.go b/src/pkg/crypto/tls/prf_test.go
index d99bab5..f8c4acb 100644
--- a/src/pkg/crypto/tls/prf_test.go
+++ b/src/pkg/crypto/tls/prf_test.go
@@ -47,7 +47,7 @@
 		in, _ := hex.DecodeString(test.preMasterSecret)
 		clientRandom, _ := hex.DecodeString(test.clientRandom)
 		serverRandom, _ := hex.DecodeString(test.serverRandom)
-		master, clientMAC, serverMAC, clientKey, serverKey := keysFromPreMasterSecret11(in, clientRandom, serverRandom, test.macLen, test.keyLen)
+		master, clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromPreMasterSecret10(in, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
 		masterString := hex.EncodeToString(master)
 		clientMACString := hex.EncodeToString(clientMAC)
 		serverMACString := hex.EncodeToString(serverMAC)