The Go Programming Language

Source file src/pkg/crypto/tls/handshake_server.go

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package tls
     6	
     7	import (
     8		"crypto"
     9		"crypto/rsa"
    10		"crypto/subtle"
    11		"crypto/x509"
    12		"io"
    13		"os"
    14	)
    15	
    16	func (c *Conn) serverHandshake() os.Error {
    17		config := c.config
    18		msg, err := c.readHandshake()
    19		if err != nil {
    20			return err
    21		}
    22		clientHello, ok := msg.(*clientHelloMsg)
    23		if !ok {
    24			return c.sendAlert(alertUnexpectedMessage)
    25		}
    26		vers, ok := mutualVersion(clientHello.vers)
    27		if !ok {
    28			return c.sendAlert(alertProtocolVersion)
    29		}
    30		c.vers = vers
    31		c.haveVers = true
    32	
    33		finishedHash := newFinishedHash()
    34		finishedHash.Write(clientHello.marshal())
    35	
    36		hello := new(serverHelloMsg)
    37	
    38		supportedCurve := false
    39	Curves:
    40		for _, curve := range clientHello.supportedCurves {
    41			switch curve {
    42			case curveP256, curveP384, curveP521:
    43				supportedCurve = true
    44				break Curves
    45			}
    46		}
    47	
    48		supportedPointFormat := false
    49		for _, pointFormat := range clientHello.supportedPoints {
    50			if pointFormat == pointFormatUncompressed {
    51				supportedPointFormat = true
    52				break
    53			}
    54		}
    55	
    56		ellipticOk := supportedCurve && supportedPointFormat
    57	
    58		var suite *cipherSuite
    59		var suiteId uint16
    60	FindCipherSuite:
    61		for _, id := range clientHello.cipherSuites {
    62			for _, supported := range config.cipherSuites() {
    63				if id == supported {
    64					suite = cipherSuites[id]
    65					// Don't select a ciphersuite which we can't
    66					// support for this client.
    67					if suite.elliptic && !ellipticOk {
    68						continue
    69					}
    70					suiteId = id
    71					break FindCipherSuite
    72				}
    73			}
    74		}
    75	
    76		foundCompression := false
    77		// We only support null compression, so check that the client offered it.
    78		for _, compression := range clientHello.compressionMethods {
    79			if compression == compressionNone {
    80				foundCompression = true
    81				break
    82			}
    83		}
    84	
    85		if suite == nil || !foundCompression {
    86			return c.sendAlert(alertHandshakeFailure)
    87		}
    88	
    89		hello.vers = vers
    90		hello.cipherSuite = suiteId
    91		t := uint32(config.time())
    92		hello.random = make([]byte, 32)
    93		hello.random[0] = byte(t >> 24)
    94		hello.random[1] = byte(t >> 16)
    95		hello.random[2] = byte(t >> 8)
    96		hello.random[3] = byte(t)
    97		_, err = io.ReadFull(config.rand(), hello.random[4:])
    98		if err != nil {
    99			return c.sendAlert(alertInternalError)
   100		}
   101		hello.compressionMethod = compressionNone
   102		if clientHello.nextProtoNeg {
   103			hello.nextProtoNeg = true
   104			hello.nextProtos = config.NextProtos
   105		}
   106		if clientHello.ocspStapling && len(config.Certificates[0].OCSPStaple) > 0 {
   107			hello.ocspStapling = true
   108		}
   109	
   110		finishedHash.Write(hello.marshal())
   111		c.writeRecord(recordTypeHandshake, hello.marshal())
   112	
   113		if len(config.Certificates) == 0 {
   114			return c.sendAlert(alertInternalError)
   115		}
   116	
   117		certMsg := new(certificateMsg)
   118		certMsg.certificates = config.Certificates[0].Certificate
   119		finishedHash.Write(certMsg.marshal())
   120		c.writeRecord(recordTypeHandshake, certMsg.marshal())
   121	
   122		if hello.ocspStapling {
   123			certStatus := new(certificateStatusMsg)
   124			certStatus.statusType = statusTypeOCSP
   125			certStatus.response = config.Certificates[0].OCSPStaple
   126			finishedHash.Write(certStatus.marshal())
   127			c.writeRecord(recordTypeHandshake, certStatus.marshal())
   128		}
   129	
   130		keyAgreement := suite.ka()
   131	
   132		skx, err := keyAgreement.generateServerKeyExchange(config, clientHello, hello)
   133		if err != nil {
   134			c.sendAlert(alertHandshakeFailure)
   135			return err
   136		}
   137		if skx != nil {
   138			finishedHash.Write(skx.marshal())
   139			c.writeRecord(recordTypeHandshake, skx.marshal())
   140		}
   141	
   142		if config.AuthenticateClient {
   143			// Request a client certificate
   144			certReq := new(certificateRequestMsg)
   145			certReq.certificateTypes = []byte{certTypeRSASign}
   146			// An empty list of certificateAuthorities signals to
   147			// the client that it may send any certificate in response
   148			// to our request.
   149	
   150			finishedHash.Write(certReq.marshal())
   151			c.writeRecord(recordTypeHandshake, certReq.marshal())
   152		}
   153	
   154		helloDone := new(serverHelloDoneMsg)
   155		finishedHash.Write(helloDone.marshal())
   156		c.writeRecord(recordTypeHandshake, helloDone.marshal())
   157	
   158		var pub *rsa.PublicKey
   159		if config.AuthenticateClient {
   160			// Get client certificate
   161			msg, err = c.readHandshake()
   162			if err != nil {
   163				return err
   164			}
   165			certMsg, ok = msg.(*certificateMsg)
   166			if !ok {
   167				return c.sendAlert(alertUnexpectedMessage)
   168			}
   169			finishedHash.Write(certMsg.marshal())
   170	
   171			certs := make([]*x509.Certificate, len(certMsg.certificates))
   172			for i, asn1Data := range certMsg.certificates {
   173				cert, err := x509.ParseCertificate(asn1Data)
   174				if err != nil {
   175					c.sendAlert(alertBadCertificate)
   176					return os.NewError("could not parse client's certificate: " + err.String())
   177				}
   178				certs[i] = cert
   179			}
   180	
   181			// TODO(agl): do better validation of certs: max path length, name restrictions etc.
   182			for i := 1; i < len(certs); i++ {
   183				if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil {
   184					c.sendAlert(alertBadCertificate)
   185					return os.NewError("could not validate certificate signature: " + err.String())
   186				}
   187			}
   188	
   189			if len(certs) > 0 {
   190				key, ok := certs[0].PublicKey.(*rsa.PublicKey)
   191				if !ok {
   192					return c.sendAlert(alertUnsupportedCertificate)
   193				}
   194				pub = key
   195				c.peerCertificates = certs
   196			}
   197		}
   198	
   199		// Get client key exchange
   200		msg, err = c.readHandshake()
   201		if err != nil {
   202			return err
   203		}
   204		ckx, ok := msg.(*clientKeyExchangeMsg)
   205		if !ok {
   206			return c.sendAlert(alertUnexpectedMessage)
   207		}
   208		finishedHash.Write(ckx.marshal())
   209	
   210		// If we received a client cert in response to our certificate request message,
   211		// the client will send us a certificateVerifyMsg immediately after the
   212		// clientKeyExchangeMsg.  This message is a MD5SHA1 digest of all preceding
   213		// handshake-layer messages that is signed using the private key corresponding
   214		// to the client's certificate. This allows us to verify that the client is in
   215		// possession of the private key of the certificate.
   216		if len(c.peerCertificates) > 0 {
   217			msg, err = c.readHandshake()
   218			if err != nil {
   219				return err
   220			}
   221			certVerify, ok := msg.(*certificateVerifyMsg)
   222			if !ok {
   223				return c.sendAlert(alertUnexpectedMessage)
   224			}
   225	
   226			digest := make([]byte, 36)
   227			copy(digest[0:16], finishedHash.serverMD5.Sum())
   228			copy(digest[16:36], finishedHash.serverSHA1.Sum())
   229			err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature)
   230			if err != nil {
   231				c.sendAlert(alertBadCertificate)
   232				return os.NewError("could not validate signature of connection nonces: " + err.String())
   233			}
   234	
   235			finishedHash.Write(certVerify.marshal())
   236		}
   237	
   238		preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx)
   239		if err != nil {
   240			c.sendAlert(alertHandshakeFailure)
   241			return err
   242		}
   243	
   244		masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
   245			keysFromPreMasterSecret10(preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)
   246	
   247		clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */ )
   248		clientHash := suite.mac(clientMAC)
   249		c.in.prepareCipherSpec(clientCipher, clientHash)
   250		c.readRecord(recordTypeChangeCipherSpec)
   251		if err := c.error(); err != nil {
   252			return err
   253		}
   254	
   255		if hello.nextProtoNeg {
   256			msg, err = c.readHandshake()
   257			if err != nil {
   258				return err
   259			}
   260			nextProto, ok := msg.(*nextProtoMsg)
   261			if !ok {
   262				return c.sendAlert(alertUnexpectedMessage)
   263			}
   264			finishedHash.Write(nextProto.marshal())
   265			c.clientProtocol = nextProto.proto
   266		}
   267	
   268		msg, err = c.readHandshake()
   269		if err != nil {
   270			return err
   271		}
   272		clientFinished, ok := msg.(*finishedMsg)
   273		if !ok {
   274			return c.sendAlert(alertUnexpectedMessage)
   275		}
   276	
   277		verify := finishedHash.clientSum(masterSecret)
   278		if len(verify) != len(clientFinished.verifyData) ||
   279			subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
   280			return c.sendAlert(alertHandshakeFailure)
   281		}
   282	
   283		finishedHash.Write(clientFinished.marshal())
   284	
   285		serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */ )
   286		serverHash := suite.mac(serverMAC)
   287		c.out.prepareCipherSpec(serverCipher, serverHash)
   288		c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
   289	
   290		finished := new(finishedMsg)
   291		finished.verifyData = finishedHash.serverSum(masterSecret)
   292		c.writeRecord(recordTypeHandshake, finished.marshal())
   293	
   294		c.handshakeComplete = true
   295		c.cipherSuite = suiteId
   296	
   297		return nil
   298	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.