diff options
| author | Russ Cox <rsc@golang.org> | 2010-04-26 22:19:04 -0700 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2010-04-26 22:19:04 -0700 |
| commit | 95e18c29897387f28e3e73cd164474977ff56582 (patch) | |
| tree | bfe11232af96d9016ebbe9175bb12b795a3008e5 /src/pkg/crypto/tls/handshake_client.go | |
| parent | 0415bdc67536a8d8c51aa26f2cd9b9cdf2d3967b (diff) | |
| download | golang-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.go | 188 |
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 } |
