Exemple #1
0
func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg, version uint16) ([]byte, os.Error) {
	preMasterSecret := make([]byte, 48)
	_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
	if err != nil {
		return nil, err
	}

	if len(ckx.ciphertext) < 2 {
		return nil, os.NewError("bad ClientKeyExchange")
	}

	ciphertext := ckx.ciphertext
	if version != versionSSL30 {
		ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
		if ciphertextLen != len(ckx.ciphertext)-2 {
			return nil, os.NewError("bad ClientKeyExchange")
		}
		ciphertext = ckx.ciphertext[2:]
	}

	err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ciphertext, preMasterSecret)
	if err != nil {
		return nil, err
	}
	// We don't check the version number in the premaster secret.  For one,
	// by checking it, we would leak information about the validity of the
	// encrypted pre-master secret. Secondly, it provides only a small
	// benefit against a downgrade attack and some implementations send the
	// wrong version anyway. See the discussion at the end of section
	// 7.4.7.1 of RFC 4346.
	return preMasterSecret, nil
}
Exemple #2
0
// KeyDecrypt decryptes the encrypted key using RSA PKCS1v1.5
func (d RSAPKCS15KeyDecrypt) KeyDecrypt(enckey []byte) ([]byte, error) {
	if debug.Enabled {
		debug.Printf("START PKCS.KeyDecrypt")
	}
	// Hey, these notes and workarounds were stolen from go-jose
	defer func() {
		// DecryptPKCS1v15SessionKey sometimes panics on an invalid payload
		// because of an index out of bounds error, which we want to ignore.
		// This has been fixed in Go 1.3.1 (released 2014/08/13), the recover()
		// only exists for preventing crashes with unpatched versions.
		// See: https://groups.google.com/forum/#!topic/golang-dev/7ihX6Y6kx9k
		// See: https://code.google.com/p/go/source/detail?r=58ee390ff31602edb66af41ed10901ec95904d33
		_ = recover()
	}()

	// Perform some input validation.
	expectedlen := d.privkey.PublicKey.N.BitLen() / 8
	if expectedlen != len(enckey) {
		// Input size is incorrect, the encrypted payload should always match
		// the size of the public modulus (e.g. using a 2048 bit key will
		// produce 256 bytes of output). Reject this since it's invalid input.
		return nil, fmt.Errorf(
			"input size for key decrypt is incorrect (expected %d, got %d)",
			expectedlen,
			len(enckey),
		)
	}

	var err error

	bk, err := d.generator.KeyGenerate()
	if err != nil {
		return nil, errors.New("failed to generate key")
	}
	cek := bk.Bytes()

	// When decrypting an RSA-PKCS1v1.5 payload, we must take precautions to
	// prevent chosen-ciphertext attacks as described in RFC 3218, "Preventing
	// the Million Message Attack on Cryptographic Message Syntax". We are
	// therefore deliberatly ignoring errors here.
	err = rsa.DecryptPKCS1v15SessionKey(rand.Reader, d.privkey, enckey, cek)
	if err != nil {
		return nil, err
	}

	return cek, nil
}
Exemple #3
0
// Decrypt the given payload. Based on the key encryption algorithm,
// this will either use RSA-PKCS1v1.5 or RSA-OAEP (with SHA-1 or SHA-256).
func (ctx rsaDecrypterSigner) decrypt(jek []byte, alg KeyAlgorithm, generator keyGenerator) ([]byte, error) {
	// Note: The random reader on decrypt operations is only used for blinding,
	// so stubbing is meanlingless (hence the direct use of rand.Reader).
	switch alg {
	case RSA1_5:
		defer func() {
			// DecryptPKCS1v15SessionKey sometimes panics on an invalid payload
			// because of an index out of bounds error, which we want to ignore.
			// This has been fixed in Go 1.3.1 (released 2014/08/13), the recover()
			// only exists for preventing crashes with unpatched versions.
			// See: https://groups.google.com/forum/#!topic/golang-dev/7ihX6Y6kx9k
			// See: https://code.google.com/p/go/source/detail?r=58ee390ff31602edb66af41ed10901ec95904d33
			_ = recover()
		}()

		// Perform some input validation.
		keyBytes := ctx.privateKey.PublicKey.N.BitLen() / 8
		if keyBytes != len(jek) {
			// Input size is incorrect, the encrypted payload should always match
			// the size of the public modulus (e.g. using a 2048 bit key will
			// produce 256 bytes of output). Reject this since it's invalid input.
			return nil, ErrCryptoFailure
		}

		cek, _, err := generator.genKey()
		if err != nil {
			return nil, ErrCryptoFailure
		}

		// When decrypting an RSA-PKCS1v1.5 payload, we must take precautions to
		// prevent chosen-ciphertext attacks as described in RFC 3218, "Preventing
		// the Million Message Attack on Cryptographic Message Syntax". We are
		// therefore deliberately ignoring errors here.
		_ = rsa.DecryptPKCS1v15SessionKey(rand.Reader, ctx.privateKey, jek, cek)

		return cek, nil
	case RSA_OAEP:
		// Use rand.Reader for RSA blinding
		return rsa.DecryptOAEP(sha1.New(), rand.Reader, ctx.privateKey, jek, []byte{})
	case RSA_OAEP_256:
		// Use rand.Reader for RSA blinding
		return rsa.DecryptOAEP(sha256.New(), rand.Reader, ctx.privateKey, jek, []byte{})
	}

	return nil, ErrUnsupportedAlgorithm
}
Exemple #4
0
func (ka *rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
	preMasterSecret := make([]byte, 48)
	_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
	if err != nil {
		return nil, err
	}

	if len(ckx.ciphertext) < 2 {
		return nil, errClientKeyExchange
	}

	ciphertext := ckx.ciphertext
	if version != VersionSSL30 {
		ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
		if ciphertextLen != len(ckx.ciphertext)-2 {
			return nil, errClientKeyExchange
		}
		ciphertext = ckx.ciphertext[2:]
	}

	key := cert.PrivateKey.(*rsa.PrivateKey)
	if ka.exportKey != nil {
		key = ka.exportKey
	}
	err = rsa.DecryptPKCS1v15SessionKey(config.rand(), key, ciphertext, preMasterSecret)
	if err != nil {
		return nil, err
	}
	// This check should be done in constant-time, but this is a testing
	// implementation. See the discussion at the end of section 7.4.7.1 of
	// RFC 4346.
	vers := uint16(preMasterSecret[0])<<8 | uint16(preMasterSecret[1])
	if ka.clientVersion != vers {
		return nil, fmt.Errorf("tls: invalid version in RSA premaster (got %04x, wanted %04x)", vers, ka.clientVersion)
	}
	return preMasterSecret, nil
}
func (h *serverHandshake) loop(writeChan chan<- interface{}, controlChan chan<- interface{}, msgChan <-chan interface{}, config *Config) {
	h.writeChan = writeChan
	h.controlChan = controlChan
	h.msgChan = msgChan
	h.config = config

	defer close(writeChan)
	defer close(controlChan)

	clientHello, ok := h.readHandshakeMsg().(*clientHelloMsg)
	if !ok {
		h.error(alertUnexpectedMessage)
		return
	}
	major, minor, ok := mutualVersion(clientHello.major, clientHello.minor)
	if !ok {
		h.error(alertProtocolVersion)
		return
	}

	finishedHash := newFinishedHash()
	finishedHash.Write(clientHello.marshal())

	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

	for _, id := range clientHello.cipherSuites {
		for _, supported := range cipherSuites {
			if supported.id == id {
				suite = &supported
				break
			}
		}
	}

	foundCompression := false
	// We only support null compression, so check that the client offered it.
	for _, compression := range clientHello.compressionMethods {
		if compression == compressionNone {
			foundCompression = true
			break
		}
	}

	if suite == nil || !foundCompression {
		h.error(alertHandshakeFailure)
		return
	}

	hello.major = major
	hello.minor = minor
	hello.cipherSuite = suite.id
	currentTime := uint32(config.Time())
	hello.random = make([]byte, 32)
	hello.random[0] = byte(currentTime >> 24)
	hello.random[1] = byte(currentTime >> 16)
	hello.random[2] = byte(currentTime >> 8)
	hello.random[3] = byte(currentTime)
	_, err := io.ReadFull(config.Rand, hello.random[4:])
	if err != nil {
		h.error(alertInternalError)
		return
	}
	hello.compressionMethod = compressionNone
	if clientHello.nextProtoNeg {
		hello.nextProtoNeg = true
		hello.nextProtos = config.NextProtos
	}

	finishedHash.Write(hello.marshal())
	writeChan <- writerSetVersion{major, minor}
	writeChan <- hello

	if len(config.Certificates) == 0 {
		h.error(alertInternalError)
		return
	}

	certMsg := new(certificateMsg)
	certMsg.certificates = config.Certificates[0].Certificate
	finishedHash.Write(certMsg.marshal())
	writeChan <- certMsg

	helloDone := new(serverHelloDoneMsg)
	finishedHash.Write(helloDone.marshal())
	writeChan <- helloDone

	ckx, ok := h.readHandshakeMsg().(*clientKeyExchangeMsg)
	if !ok {
		h.error(alertUnexpectedMessage)
		return
	}
	finishedHash.Write(ckx.marshal())

	preMasterSecret := make([]byte, 48)
	_, err = io.ReadFull(config.Rand, preMasterSecret[2:])
	if err != nil {
		h.error(alertInternalError)
		return
	}

	err = rsa.DecryptPKCS1v15SessionKey(config.Rand, config.Certificates[0].PrivateKey, ckx.ciphertext, preMasterSecret)
	if err != nil {
		h.error(alertHandshakeFailure)
		return
	}
	// We don't check the version number in the premaster secret. For one,
	// by checking it, we would leak information about the validity of the
	// encrypted pre-master secret. Secondly, it provides only a small
	// benefit against a downgrade attack and some implementations send the
	// 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)

	_, ok = h.readHandshakeMsg().(changeCipherSpec)
	if !ok {
		h.error(alertUnexpectedMessage)
		return
	}

	cipher, _ := rc4.NewCipher(clientKey)
	controlChan <- &newCipherSpec{cipher, hmac.New(sha1.New(), clientMAC)}

	clientProtocol := ""
	if hello.nextProtoNeg {
		nextProto, ok := h.readHandshakeMsg().(*nextProtoMsg)
		if !ok {
			h.error(alertUnexpectedMessage)
			return
		}
		finishedHash.Write(nextProto.marshal())
		clientProtocol = nextProto.proto
	}

	clientFinished, ok := h.readHandshakeMsg().(*finishedMsg)
	if !ok {
		h.error(alertUnexpectedMessage)
		return
	}

	verify := finishedHash.clientSum(masterSecret)
	if len(verify) != len(clientFinished.verifyData) ||
		subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
		h.error(alertHandshakeFailure)
		return
	}

	controlChan <- ConnectionState{true, "TLS_RSA_WITH_RC4_128_SHA", 0, clientProtocol}

	finishedHash.Write(clientFinished.marshal())

	cipher2, _ := rc4.NewCipher(serverKey)
	writeChan <- writerChangeCipherSpec{cipher2, hmac.New(sha1.New(), serverMAC)}

	finished := new(finishedMsg)
	finished.verifyData = finishedHash.serverSum(masterSecret)
	writeChan <- finished

	writeChan <- writerEnableApplicationData{}

	for {
		_, ok := h.readHandshakeMsg().(*clientHelloMsg)
		if !ok {
			h.error(alertUnexpectedMessage)
			return
		}
		// We reject all renegotication requests.
		writeChan <- alert{alertLevelWarning, alertNoRenegotiation}
	}
}
func (c *Conn) serverHandshake() os.Error {
	config := c.config
	msg, err := c.readHandshake()
	if err != nil {
		return err
	}
	clientHello, ok := msg.(*clientHelloMsg)
	if !ok {
		return c.sendAlert(alertUnexpectedMessage)
	}
	vers, ok := mutualVersion(clientHello.vers)
	if !ok {
		return c.sendAlert(alertProtocolVersion)
	}
	c.vers = vers
	c.haveVers = true

	finishedHash := newFinishedHash()
	finishedHash.Write(clientHello.marshal())

	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

	for _, id := range clientHello.cipherSuites {
		for _, supported := range cipherSuites {
			if supported.id == id {
				suite = &supported
				break
			}
		}
	}

	foundCompression := false
	// We only support null compression, so check that the client offered it.
	for _, compression := range clientHello.compressionMethods {
		if compression == compressionNone {
			foundCompression = true
			break
		}
	}

	if suite == nil || !foundCompression {
		return c.sendAlert(alertHandshakeFailure)
	}

	hello.vers = vers
	hello.cipherSuite = suite.id
	t := uint32(config.Time())
	hello.random = make([]byte, 32)
	hello.random[0] = byte(t >> 24)
	hello.random[1] = byte(t >> 16)
	hello.random[2] = byte(t >> 8)
	hello.random[3] = byte(t)
	_, err = io.ReadFull(config.Rand, hello.random[4:])
	if err != nil {
		return c.sendAlert(alertInternalError)
	}
	hello.compressionMethod = compressionNone
	if clientHello.nextProtoNeg {
		hello.nextProtoNeg = true
		hello.nextProtos = config.NextProtos
	}

	finishedHash.Write(hello.marshal())
	c.writeRecord(recordTypeHandshake, hello.marshal())

	if len(config.Certificates) == 0 {
		return c.sendAlert(alertInternalError)
	}

	certMsg := new(certificateMsg)
	certMsg.certificates = config.Certificates[0].Certificate
	finishedHash.Write(certMsg.marshal())
	c.writeRecord(recordTypeHandshake, certMsg.marshal())

	if config.AuthenticateClient {
		// Request a client certificate
		certReq := new(certificateRequestMsg)
		certReq.certificateTypes = []byte{certTypeRSASign}
		// An empty list of certificateAuthorities signals to
		// the client that it may send any certificate in response
		// to our request.

		finishedHash.Write(certReq.marshal())
		c.writeRecord(recordTypeHandshake, certReq.marshal())
	}

	helloDone := new(serverHelloDoneMsg)
	finishedHash.Write(helloDone.marshal())
	c.writeRecord(recordTypeHandshake, helloDone.marshal())

	var pub *rsa.PublicKey
	if config.AuthenticateClient {
		// Get client certificate
		msg, err = c.readHandshake()
		if err != nil {
			return err
		}
		certMsg, ok = msg.(*certificateMsg)
		if !ok {
			return c.sendAlert(alertUnexpectedMessage)
		}
		finishedHash.Write(certMsg.marshal())

		certs := make([]*x509.Certificate, len(certMsg.certificates))
		for i, asn1Data := range certMsg.certificates {
			cert, err := x509.ParseCertificate(asn1Data)
			if err != nil {
				c.sendAlert(alertBadCertificate)
				return os.ErrorString("could not parse client's certificate: " + err.String())
			}
			certs[i] = cert
		}

		// TODO(agl): do better validation of certs: max path length, name restrictions etc.
		for i := 1; i < len(certs); i++ {
			if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil {
				c.sendAlert(alertBadCertificate)
				return os.ErrorString("could not validate certificate signature: " + err.String())
			}
		}

		if len(certs) > 0 {
			key, ok := certs[0].PublicKey.(*rsa.PublicKey)
			if !ok {
				return c.sendAlert(alertUnsupportedCertificate)
			}
			pub = key
			c.peerCertificates = certs
		}
	}

	// Get client key exchange
	msg, err = c.readHandshake()
	if err != nil {
		return err
	}
	ckx, ok := msg.(*clientKeyExchangeMsg)
	if !ok {
		return c.sendAlert(alertUnexpectedMessage)
	}
	finishedHash.Write(ckx.marshal())

	// If we received a client cert in response to our certificate request message,
	// the client will send us a certificateVerifyMsg immediately after the
	// clientKeyExchangeMsg.  This message is a MD5SHA1 digest of all preceeding
	// handshake-layer messages that is signed using the private key corresponding
	// to the client's certificate. This allows us to verify that the client is in
	// posession of the private key of the certificate.
	if len(c.peerCertificates) > 0 {
		msg, err = c.readHandshake()
		if err != nil {
			return err
		}
		certVerify, ok := msg.(*certificateVerifyMsg)
		if !ok {
			return c.sendAlert(alertUnexpectedMessage)
		}

		digest := make([]byte, 36)
		copy(digest[0:16], finishedHash.serverMD5.Sum())
		copy(digest[16:36], finishedHash.serverSHA1.Sum())
		err = rsa.VerifyPKCS1v15(pub, rsa.HashMD5SHA1, digest, certVerify.signature)
		if err != nil {
			c.sendAlert(alertBadCertificate)
			return os.ErrorString("could not validate signature of connection nonces: " + err.String())
		}

		finishedHash.Write(certVerify.marshal())
	}

	preMasterSecret := make([]byte, 48)
	_, err = io.ReadFull(config.Rand, preMasterSecret[2:])
	if err != nil {
		return c.sendAlert(alertInternalError)
	}

	err = rsa.DecryptPKCS1v15SessionKey(config.Rand, config.Certificates[0].PrivateKey, ckx.ciphertext, preMasterSecret)
	if err != nil {
		return c.sendAlert(alertHandshakeFailure)
	}
	// We don't check the version number in the premaster secret. For one,
	// by checking it, we would leak information about the validity of the
	// encrypted pre-master secret. Secondly, it provides only a small
	// benefit against a downgrade attack and some implementations send the
	// 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)

	cipher, _ := rc4.NewCipher(clientKey)
	c.in.prepareCipherSpec(cipher, hmac.NewSHA1(clientMAC))
	c.readRecord(recordTypeChangeCipherSpec)
	if err := c.error(); err != nil {
		return err
	}

	if hello.nextProtoNeg {
		msg, err = c.readHandshake()
		if err != nil {
			return err
		}
		nextProto, ok := msg.(*nextProtoMsg)
		if !ok {
			return c.sendAlert(alertUnexpectedMessage)
		}
		finishedHash.Write(nextProto.marshal())
		c.clientProtocol = nextProto.proto
	}

	msg, err = c.readHandshake()
	if err != nil {
		return err
	}
	clientFinished, ok := msg.(*finishedMsg)
	if !ok {
		return c.sendAlert(alertUnexpectedMessage)
	}

	verify := finishedHash.clientSum(masterSecret)
	if len(verify) != len(clientFinished.verifyData) ||
		subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
		return c.sendAlert(alertHandshakeFailure)
	}

	finishedHash.Write(clientFinished.marshal())

	cipher2, _ := rc4.NewCipher(serverKey)
	c.out.prepareCipherSpec(cipher2, hmac.NewSHA1(serverMAC))
	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})

	finished := new(finishedMsg)
	finished.verifyData = finishedHash.serverSum(masterSecret)
	c.writeRecord(recordTypeHandshake, finished.marshal())

	c.handshakeComplete = true
	c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA

	return nil
}
func (c *Conn) serverHandshake() os.Error {
	config := c.config
	msg, err := c.readHandshake()
	if err != nil {
		return err
	}
	clientHello, ok := msg.(*clientHelloMsg)
	if !ok {
		return c.sendAlert(alertUnexpectedMessage)
	}
	vers, ok := mutualVersion(clientHello.vers)
	if !ok {
		return c.sendAlert(alertProtocolVersion)
	}
	c.vers = vers
	c.haveVers = true

	finishedHash := newFinishedHash()
	finishedHash.Write(clientHello.marshal())

	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

	for _, id := range clientHello.cipherSuites {
		for _, supported := range cipherSuites {
			if supported.id == id {
				suite = &supported
				break
			}
		}
	}

	foundCompression := false
	// We only support null compression, so check that the client offered it.
	for _, compression := range clientHello.compressionMethods {
		if compression == compressionNone {
			foundCompression = true
			break
		}
	}

	if suite == nil || !foundCompression {
		return c.sendAlert(alertHandshakeFailure)
	}

	hello.vers = vers
	hello.cipherSuite = suite.id
	t := uint32(config.Time())
	hello.random = make([]byte, 32)
	hello.random[0] = byte(t >> 24)
	hello.random[1] = byte(t >> 16)
	hello.random[2] = byte(t >> 8)
	hello.random[3] = byte(t)
	_, err = io.ReadFull(config.Rand, hello.random[4:])
	if err != nil {
		return c.sendAlert(alertInternalError)
	}
	hello.compressionMethod = compressionNone
	if clientHello.nextProtoNeg {
		hello.nextProtoNeg = true
		hello.nextProtos = config.NextProtos
	}

	finishedHash.Write(hello.marshal())
	c.writeRecord(recordTypeHandshake, hello.marshal())

	if len(config.Certificates) == 0 {
		return c.sendAlert(alertInternalError)
	}

	certMsg := new(certificateMsg)
	certMsg.certificates = config.Certificates[0].Certificate
	finishedHash.Write(certMsg.marshal())
	c.writeRecord(recordTypeHandshake, certMsg.marshal())

	helloDone := new(serverHelloDoneMsg)
	finishedHash.Write(helloDone.marshal())
	c.writeRecord(recordTypeHandshake, helloDone.marshal())

	msg, err = c.readHandshake()
	if err != nil {
		return err
	}
	ckx, ok := msg.(*clientKeyExchangeMsg)
	if !ok {
		return c.sendAlert(alertUnexpectedMessage)
	}
	finishedHash.Write(ckx.marshal())

	preMasterSecret := make([]byte, 48)
	_, err = io.ReadFull(config.Rand, preMasterSecret[2:])
	if err != nil {
		return c.sendAlert(alertInternalError)
	}

	err = rsa.DecryptPKCS1v15SessionKey(config.Rand, config.Certificates[0].PrivateKey, ckx.ciphertext, preMasterSecret)
	if err != nil {
		return c.sendAlert(alertHandshakeFailure)
	}
	// We don't check the version number in the premaster secret. For one,
	// by checking it, we would leak information about the validity of the
	// encrypted pre-master secret. Secondly, it provides only a small
	// benefit against a downgrade attack and some implementations send the
	// 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)

	cipher, _ := rc4.NewCipher(clientKey)
	c.in.prepareCipherSpec(cipher, hmac.New(sha1.New(), clientMAC))
	c.readRecord(recordTypeChangeCipherSpec)
	if err := c.error(); err != nil {
		return err
	}

	if hello.nextProtoNeg {
		msg, err = c.readHandshake()
		if err != nil {
			return err
		}
		nextProto, ok := msg.(*nextProtoMsg)
		if !ok {
			return c.sendAlert(alertUnexpectedMessage)
		}
		finishedHash.Write(nextProto.marshal())
		c.clientProtocol = nextProto.proto
	}

	msg, err = c.readHandshake()
	if err != nil {
		return err
	}
	clientFinished, ok := msg.(*finishedMsg)
	if !ok {
		return c.sendAlert(alertUnexpectedMessage)
	}

	verify := finishedHash.clientSum(masterSecret)
	if len(verify) != len(clientFinished.verifyData) ||
		subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
		return c.sendAlert(alertHandshakeFailure)
	}

	finishedHash.Write(clientFinished.marshal())

	cipher2, _ := rc4.NewCipher(serverKey)
	c.out.prepareCipherSpec(cipher2, hmac.New(sha1.New(), serverMAC))
	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})

	finished := new(finishedMsg)
	finished.verifyData = finishedHash.serverSum(masterSecret)
	c.writeRecord(recordTypeHandshake, finished.marshal())

	c.handshakeComplete = true
	c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA

	return nil
}