summaryrefslogtreecommitdiff
path: root/src/pkg/crypto/tls/handshake_client.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2010-04-26 22:19:04 -0700
committerRuss Cox <rsc@golang.org>2010-04-26 22:19:04 -0700
commit95e18c29897387f28e3e73cd164474977ff56582 (patch)
treebfe11232af96d9016ebbe9175bb12b795a3008e5 /src/pkg/crypto/tls/handshake_client.go
parent0415bdc67536a8d8c51aa26f2cd9b9cdf2d3967b (diff)
downloadgolang-95e18c29897387f28e3e73cd164474977ff56582.tar.gz
crypto/tls: simpler implementation of record layer
Depends on CL 957045, 980043, 1004043. Fixes issue 715. R=agl1, agl CC=golang-dev http://codereview.appspot.com/943043
Diffstat (limited to 'src/pkg/crypto/tls/handshake_client.go')
-rw-r--r--src/pkg/crypto/tls/handshake_client.go188
1 files changed, 68 insertions, 120 deletions
diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go
index 8cc6b7409..dd3009802 100644
--- a/src/pkg/crypto/tls/handshake_client.go
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -12,74 +12,63 @@ import (
"crypto/subtle"
"crypto/x509"
"io"
+ "os"
)
-// A serverHandshake performs the server side of the TLS 1.1 handshake protocol.
-type clientHandshake struct {
- writeChan chan<- interface{}
- controlChan chan<- interface{}
- msgChan <-chan interface{}
- config *Config
-}
-
-func (h *clientHandshake) 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)
-
+func (c *Conn) clientHandshake() os.Error {
finishedHash := newFinishedHash()
+ config := defaultConfig()
+
hello := &clientHelloMsg{
- major: defaultMajor,
- minor: defaultMinor,
+ vers: maxVersion,
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
}
- currentTime := uint32(config.Time())
- hello.random[0] = byte(currentTime >> 24)
- hello.random[1] = byte(currentTime >> 16)
- hello.random[2] = byte(currentTime >> 8)
- hello.random[3] = byte(currentTime)
+ t := uint32(config.Time())
+ 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 {
- h.error(alertInternalError)
- return
+ return c.sendAlert(alertInternalError)
}
finishedHash.Write(hello.marshal())
- writeChan <- writerSetVersion{defaultMajor, defaultMinor}
- writeChan <- hello
+ c.writeRecord(recordTypeHandshake, hello.marshal())
- serverHello, ok := h.readHandshakeMsg().(*serverHelloMsg)
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ serverHello, ok := msg.(*serverHelloMsg)
if !ok {
- h.error(alertUnexpectedMessage)
- return
+ return c.sendAlert(alertUnexpectedMessage)
}
finishedHash.Write(serverHello.marshal())
- major, minor, ok := mutualVersion(serverHello.major, serverHello.minor)
+
+ vers, ok := mutualVersion(serverHello.vers)
if !ok {
- h.error(alertProtocolVersion)
- return
+ c.sendAlert(alertProtocolVersion)
}
-
- writeChan <- writerSetVersion{major, minor}
+ c.vers = vers
+ c.haveVers = true
if serverHello.cipherSuite != TLS_RSA_WITH_RC4_128_SHA ||
serverHello.compressionMethod != compressionNone {
- h.error(alertUnexpectedMessage)
- return
+ return c.sendAlert(alertUnexpectedMessage)
}
- certMsg, ok := h.readHandshakeMsg().(*certificateMsg)
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ certMsg, ok := msg.(*certificateMsg)
if !ok || len(certMsg.certificates) == 0 {
- h.error(alertUnexpectedMessage)
- return
+ return c.sendAlert(alertUnexpectedMessage)
}
finishedHash.Write(certMsg.marshal())
@@ -87,139 +76,98 @@ func (h *clientHandshake) loop(writeChan chan<- interface{}, controlChan chan<-
for i, asn1Data := range certMsg.certificates {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
- h.error(alertBadCertificate)
- return
+ return c.sendAlert(alertBadCertificate)
}
certs[i] = cert
}
// TODO(agl): do better validation of certs: max path length, name restrictions etc.
for i := 1; i < len(certs); i++ {
- if certs[i-1].CheckSignatureFrom(certs[i]) != nil {
- h.error(alertBadCertificate)
- return
+ if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil {
+ return c.sendAlert(alertBadCertificate)
}
}
- if config.RootCAs != nil {
+ // TODO(rsc): Find certificates for OS X 10.6.
+ if false && config.RootCAs != nil {
root := config.RootCAs.FindParent(certs[len(certs)-1])
if root == nil {
- h.error(alertBadCertificate)
- return
+ return c.sendAlert(alertBadCertificate)
}
if certs[len(certs)-1].CheckSignatureFrom(root) != nil {
- h.error(alertBadCertificate)
- return
+ return c.sendAlert(alertBadCertificate)
}
}
pub, ok := certs[0].PublicKey.(*rsa.PublicKey)
if !ok {
- h.error(alertUnsupportedCertificate)
- return
+ return c.sendAlert(alertUnsupportedCertificate)
}
- shd, ok := h.readHandshakeMsg().(*serverHelloDoneMsg)
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ shd, ok := msg.(*serverHelloDoneMsg)
if !ok {
- h.error(alertUnexpectedMessage)
- return
+ return c.sendAlert(alertUnexpectedMessage)
}
finishedHash.Write(shd.marshal())
ckx := new(clientKeyExchangeMsg)
preMasterSecret := make([]byte, 48)
- // Note that the version number in the preMasterSecret must be the
- // version offered in the ClientHello.
- preMasterSecret[0] = defaultMajor
- preMasterSecret[1] = defaultMinor
+ preMasterSecret[0] = byte(hello.vers >> 8)
+ preMasterSecret[1] = byte(hello.vers)
_, err = io.ReadFull(config.Rand, preMasterSecret[2:])
if err != nil {
- h.error(alertInternalError)
- return
+ return c.sendAlert(alertInternalError)
}
ckx.ciphertext, err = rsa.EncryptPKCS1v15(config.Rand, pub, preMasterSecret)
if err != nil {
- h.error(alertInternalError)
- return
+ return c.sendAlert(alertInternalError)
}
finishedHash.Write(ckx.marshal())
- writeChan <- ckx
+ c.writeRecord(recordTypeHandshake, ckx.marshal())
suite := cipherSuites[0]
masterSecret, clientMAC, serverMAC, clientKey, serverKey :=
keysFromPreMasterSecret11(preMasterSecret, hello.random, serverHello.random, suite.hashLength, suite.cipherKeyLength)
cipher, _ := rc4.NewCipher(clientKey)
- writeChan <- writerChangeCipherSpec{cipher, hmac.New(sha1.New(), clientMAC)}
+
+ c.out.prepareCipherSpec(cipher, hmac.New(sha1.New(), clientMAC))
+ c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
finished := new(finishedMsg)
finished.verifyData = finishedHash.clientSum(masterSecret)
finishedHash.Write(finished.marshal())
- writeChan <- finished
-
- // TODO(agl): this is cut-through mode which should probably be an option.
- writeChan <- writerEnableApplicationData{}
-
- _, ok = h.readHandshakeMsg().(changeCipherSpec)
- if !ok {
- h.error(alertUnexpectedMessage)
- return
- }
+ c.writeRecord(recordTypeHandshake, finished.marshal())
cipher2, _ := rc4.NewCipher(serverKey)
- controlChan <- &newCipherSpec{cipher2, hmac.New(sha1.New(), serverMAC)}
+ c.in.prepareCipherSpec(cipher2, hmac.New(sha1.New(), serverMAC))
+ c.readRecord(recordTypeChangeCipherSpec)
+ if c.err != nil {
+ return c.err
+ }
- serverFinished, ok := h.readHandshakeMsg().(*finishedMsg)
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ serverFinished, ok := msg.(*finishedMsg)
if !ok {
- h.error(alertUnexpectedMessage)
- return
+ return c.sendAlert(alertUnexpectedMessage)
}
verify := finishedHash.serverSum(masterSecret)
if len(verify) != len(serverFinished.verifyData) ||
subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
- h.error(alertHandshakeFailure)
- return
+ return c.sendAlert(alertHandshakeFailure)
}
- controlChan <- ConnectionState{HandshakeComplete: true, CipherSuite: "TLS_RSA_WITH_RC4_128_SHA"}
-
- // This should just block forever.
- _ = h.readHandshakeMsg()
- h.error(alertUnexpectedMessage)
- return
-}
-
-func (h *clientHandshake) readHandshakeMsg() interface{} {
- v := <-h.msgChan
- if closed(h.msgChan) {
- // If the channel closed then the processor received an error
- // from the peer and we don't want to echo it back to them.
- h.msgChan = nil
- return 0
- }
- if _, ok := v.(alert); ok {
- // We got an alert from the processor. We forward to the writer
- // and shutdown.
- h.writeChan <- v
- h.msgChan = nil
- return 0
- }
- return v
-}
-
-func (h *clientHandshake) error(e alertType) {
- if h.msgChan != nil {
- // If we didn't get an error from the processor, then we need
- // to tell it about the error.
- go func() {
- for _ = range h.msgChan {
- }
- }()
- h.controlChan <- ConnectionState{Error: e}
- close(h.controlChan)
- h.writeChan <- alert{alertLevelError, e}
- }
+ c.handshakeComplete = true
+ c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA
+ return nil
}