github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/crypto/tls/handshake_client.go (about)

     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  	"bytes"
     9  	"crypto"
    10  	"crypto/ecdsa"
    11  	"crypto/rsa"
    12  	"crypto/subtle"
    13  	"crypto/x509"
    14  	"errors"
    15  	"fmt"
    16  	"io"
    17  	"net"
    18  	"strconv"
    19  )
    20  
    21  type clientHandshakeState struct {
    22  	c            *Conn
    23  	serverHello  *serverHelloMsg
    24  	hello        *clientHelloMsg
    25  	suite        *cipherSuite
    26  	finishedHash finishedHash
    27  	masterSecret []byte
    28  	session      *ClientSessionState
    29  }
    30  
    31  func (c *Conn) clientHandshake() error {
    32  	if c.config == nil {
    33  		c.config = defaultConfig()
    34  	}
    35  
    36  	if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify {
    37  		return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
    38  	}
    39  
    40  	nextProtosLength := 0
    41  	for _, proto := range c.config.NextProtos {
    42  		if l := len(proto); l == 0 || l > 255 {
    43  			return errors.New("tls: invalid NextProtos value")
    44  		} else {
    45  			nextProtosLength += 1 + l
    46  		}
    47  	}
    48  	if nextProtosLength > 0xffff {
    49  		return errors.New("tls: NextProtos values too large")
    50  	}
    51  
    52  	hello := &clientHelloMsg{
    53  		vers:                c.config.maxVersion(),
    54  		compressionMethods:  []uint8{compressionNone},
    55  		random:              make([]byte, 32),
    56  		ocspStapling:        true,
    57  		serverName:          c.config.ServerName,
    58  		supportedCurves:     c.config.curvePreferences(),
    59  		supportedPoints:     []uint8{pointFormatUncompressed},
    60  		nextProtoNeg:        len(c.config.NextProtos) > 0,
    61  		secureRenegotiation: true,
    62  		alpnProtocols:       c.config.NextProtos,
    63  	}
    64  
    65  	possibleCipherSuites := c.config.cipherSuites()
    66  	hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
    67  
    68  NextCipherSuite:
    69  	for _, suiteId := range possibleCipherSuites {
    70  		for _, suite := range cipherSuites {
    71  			if suite.id != suiteId {
    72  				continue
    73  			}
    74  			// Don't advertise TLS 1.2-only cipher suites unless
    75  			// we're attempting TLS 1.2.
    76  			if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
    77  				continue
    78  			}
    79  			hello.cipherSuites = append(hello.cipherSuites, suiteId)
    80  			continue NextCipherSuite
    81  		}
    82  	}
    83  
    84  	_, err := io.ReadFull(c.config.rand(), hello.random)
    85  	if err != nil {
    86  		c.sendAlert(alertInternalError)
    87  		return errors.New("tls: short read from Rand: " + err.Error())
    88  	}
    89  
    90  	if hello.vers >= VersionTLS12 {
    91  		hello.signatureAndHashes = supportedSKXSignatureAlgorithms
    92  	}
    93  
    94  	var session *ClientSessionState
    95  	var cacheKey string
    96  	sessionCache := c.config.ClientSessionCache
    97  	if c.config.SessionTicketsDisabled {
    98  		sessionCache = nil
    99  	}
   100  
   101  	if sessionCache != nil {
   102  		hello.ticketSupported = true
   103  
   104  		// Try to resume a previously negotiated TLS session, if
   105  		// available.
   106  		cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
   107  		candidateSession, ok := sessionCache.Get(cacheKey)
   108  		if ok {
   109  			// Check that the ciphersuite/version used for the
   110  			// previous session are still valid.
   111  			cipherSuiteOk := false
   112  			for _, id := range hello.cipherSuites {
   113  				if id == candidateSession.cipherSuite {
   114  					cipherSuiteOk = true
   115  					break
   116  				}
   117  			}
   118  
   119  			versOk := candidateSession.vers >= c.config.minVersion() &&
   120  				candidateSession.vers <= c.config.maxVersion()
   121  			if versOk && cipherSuiteOk {
   122  				session = candidateSession
   123  			}
   124  		}
   125  	}
   126  
   127  	if session != nil {
   128  		hello.sessionTicket = session.sessionTicket
   129  		// A random session ID is used to detect when the
   130  		// server accepted the ticket and is resuming a session
   131  		// (see RFC 5077).
   132  		hello.sessionId = make([]byte, 16)
   133  		if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
   134  			c.sendAlert(alertInternalError)
   135  			return errors.New("tls: short read from Rand: " + err.Error())
   136  		}
   137  	}
   138  
   139  	c.writeRecord(recordTypeHandshake, hello.marshal())
   140  
   141  	msg, err := c.readHandshake()
   142  	if err != nil {
   143  		return err
   144  	}
   145  	serverHello, ok := msg.(*serverHelloMsg)
   146  	if !ok {
   147  		c.sendAlert(alertUnexpectedMessage)
   148  		return unexpectedMessageError(serverHello, msg)
   149  	}
   150  
   151  	vers, ok := c.config.mutualVersion(serverHello.vers)
   152  	if !ok || vers < VersionTLS10 {
   153  		// TLS 1.0 is the minimum version supported as a client.
   154  		c.sendAlert(alertProtocolVersion)
   155  		return fmt.Errorf("tls: server selected unsupported protocol version %x", serverHello.vers)
   156  	}
   157  	c.vers = vers
   158  	c.haveVers = true
   159  
   160  	suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
   161  	if suite == nil {
   162  		c.sendAlert(alertHandshakeFailure)
   163  		return fmt.Errorf("tls: server selected an unsupported cipher suite")
   164  	}
   165  
   166  	hs := &clientHandshakeState{
   167  		c:            c,
   168  		serverHello:  serverHello,
   169  		hello:        hello,
   170  		suite:        suite,
   171  		finishedHash: newFinishedHash(c.vers),
   172  		session:      session,
   173  	}
   174  
   175  	hs.finishedHash.Write(hs.hello.marshal())
   176  	hs.finishedHash.Write(hs.serverHello.marshal())
   177  
   178  	isResume, err := hs.processServerHello()
   179  	if err != nil {
   180  		return err
   181  	}
   182  
   183  	if isResume {
   184  		if err := hs.establishKeys(); err != nil {
   185  			return err
   186  		}
   187  		if err := hs.readSessionTicket(); err != nil {
   188  			return err
   189  		}
   190  		if err := hs.readFinished(c.firstFinished[:]); err != nil {
   191  			return err
   192  		}
   193  		if err := hs.sendFinished(nil); err != nil {
   194  			return err
   195  		}
   196  	} else {
   197  		if err := hs.doFullHandshake(); err != nil {
   198  			return err
   199  		}
   200  		if err := hs.establishKeys(); err != nil {
   201  			return err
   202  		}
   203  		if err := hs.sendFinished(c.firstFinished[:]); err != nil {
   204  			return err
   205  		}
   206  		if err := hs.readSessionTicket(); err != nil {
   207  			return err
   208  		}
   209  		if err := hs.readFinished(nil); err != nil {
   210  			return err
   211  		}
   212  	}
   213  
   214  	if sessionCache != nil && hs.session != nil && session != hs.session {
   215  		sessionCache.Put(cacheKey, hs.session)
   216  	}
   217  
   218  	c.didResume = isResume
   219  	c.handshakeComplete = true
   220  	c.cipherSuite = suite.id
   221  	return nil
   222  }
   223  
   224  func (hs *clientHandshakeState) doFullHandshake() error {
   225  	c := hs.c
   226  
   227  	msg, err := c.readHandshake()
   228  	if err != nil {
   229  		return err
   230  	}
   231  	certMsg, ok := msg.(*certificateMsg)
   232  	if !ok || len(certMsg.certificates) == 0 {
   233  		c.sendAlert(alertUnexpectedMessage)
   234  		return unexpectedMessageError(certMsg, msg)
   235  	}
   236  	hs.finishedHash.Write(certMsg.marshal())
   237  
   238  	certs := make([]*x509.Certificate, len(certMsg.certificates))
   239  	for i, asn1Data := range certMsg.certificates {
   240  		cert, err := x509.ParseCertificate(asn1Data)
   241  		if err != nil {
   242  			c.sendAlert(alertBadCertificate)
   243  			return errors.New("tls: failed to parse certificate from server: " + err.Error())
   244  		}
   245  		certs[i] = cert
   246  	}
   247  
   248  	if !c.config.InsecureSkipVerify {
   249  		opts := x509.VerifyOptions{
   250  			Roots:         c.config.RootCAs,
   251  			CurrentTime:   c.config.time(),
   252  			DNSName:       c.config.ServerName,
   253  			Intermediates: x509.NewCertPool(),
   254  		}
   255  
   256  		for i, cert := range certs {
   257  			if i == 0 {
   258  				continue
   259  			}
   260  			opts.Intermediates.AddCert(cert)
   261  		}
   262  		c.verifiedChains, err = certs[0].Verify(opts)
   263  		if err != nil {
   264  			c.sendAlert(alertBadCertificate)
   265  			return err
   266  		}
   267  	}
   268  
   269  	switch certs[0].PublicKey.(type) {
   270  	case *rsa.PublicKey, *ecdsa.PublicKey:
   271  		break
   272  	default:
   273  		c.sendAlert(alertUnsupportedCertificate)
   274  		return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
   275  	}
   276  
   277  	c.peerCertificates = certs
   278  
   279  	if hs.serverHello.ocspStapling {
   280  		msg, err = c.readHandshake()
   281  		if err != nil {
   282  			return err
   283  		}
   284  		cs, ok := msg.(*certificateStatusMsg)
   285  		if !ok {
   286  			c.sendAlert(alertUnexpectedMessage)
   287  			return unexpectedMessageError(cs, msg)
   288  		}
   289  		hs.finishedHash.Write(cs.marshal())
   290  
   291  		if cs.statusType == statusTypeOCSP {
   292  			c.ocspResponse = cs.response
   293  		}
   294  	}
   295  
   296  	msg, err = c.readHandshake()
   297  	if err != nil {
   298  		return err
   299  	}
   300  
   301  	keyAgreement := hs.suite.ka(c.vers)
   302  
   303  	skx, ok := msg.(*serverKeyExchangeMsg)
   304  	if ok {
   305  		hs.finishedHash.Write(skx.marshal())
   306  		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
   307  		if err != nil {
   308  			c.sendAlert(alertUnexpectedMessage)
   309  			return err
   310  		}
   311  
   312  		msg, err = c.readHandshake()
   313  		if err != nil {
   314  			return err
   315  		}
   316  	}
   317  
   318  	var chainToSend *Certificate
   319  	var certRequested bool
   320  	certReq, ok := msg.(*certificateRequestMsg)
   321  	if ok {
   322  		certRequested = true
   323  
   324  		// RFC 4346 on the certificateAuthorities field:
   325  		// A list of the distinguished names of acceptable certificate
   326  		// authorities. These distinguished names may specify a desired
   327  		// distinguished name for a root CA or for a subordinate CA;
   328  		// thus, this message can be used to describe both known roots
   329  		// and a desired authorization space. If the
   330  		// certificate_authorities list is empty then the client MAY
   331  		// send any certificate of the appropriate
   332  		// ClientCertificateType, unless there is some external
   333  		// arrangement to the contrary.
   334  
   335  		hs.finishedHash.Write(certReq.marshal())
   336  
   337  		var rsaAvail, ecdsaAvail bool
   338  		for _, certType := range certReq.certificateTypes {
   339  			switch certType {
   340  			case certTypeRSASign:
   341  				rsaAvail = true
   342  			case certTypeECDSASign:
   343  				ecdsaAvail = true
   344  			}
   345  		}
   346  
   347  		// We need to search our list of client certs for one
   348  		// where SignatureAlgorithm is acceptable to the server and the
   349  		// Issuer is in certReq.certificateAuthorities
   350  	findCert:
   351  		for i, chain := range c.config.Certificates {
   352  			if !rsaAvail && !ecdsaAvail {
   353  				continue
   354  			}
   355  
   356  			for j, cert := range chain.Certificate {
   357  				x509Cert := chain.Leaf
   358  				// parse the certificate if this isn't the leaf
   359  				// node, or if chain.Leaf was nil
   360  				if j != 0 || x509Cert == nil {
   361  					if x509Cert, err = x509.ParseCertificate(cert); err != nil {
   362  						c.sendAlert(alertInternalError)
   363  						return errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
   364  					}
   365  				}
   366  
   367  				switch {
   368  				case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
   369  				case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
   370  				default:
   371  					continue findCert
   372  				}
   373  
   374  				if len(certReq.certificateAuthorities) == 0 {
   375  					// they gave us an empty list, so just take the
   376  					// first cert from c.config.Certificates
   377  					chainToSend = &chain
   378  					break findCert
   379  				}
   380  
   381  				for _, ca := range certReq.certificateAuthorities {
   382  					if bytes.Equal(x509Cert.RawIssuer, ca) {
   383  						chainToSend = &chain
   384  						break findCert
   385  					}
   386  				}
   387  			}
   388  		}
   389  
   390  		msg, err = c.readHandshake()
   391  		if err != nil {
   392  			return err
   393  		}
   394  	}
   395  
   396  	shd, ok := msg.(*serverHelloDoneMsg)
   397  	if !ok {
   398  		c.sendAlert(alertUnexpectedMessage)
   399  		return unexpectedMessageError(shd, msg)
   400  	}
   401  	hs.finishedHash.Write(shd.marshal())
   402  
   403  	// If the server requested a certificate then we have to send a
   404  	// Certificate message, even if it's empty because we don't have a
   405  	// certificate to send.
   406  	if certRequested {
   407  		certMsg = new(certificateMsg)
   408  		if chainToSend != nil {
   409  			certMsg.certificates = chainToSend.Certificate
   410  		}
   411  		hs.finishedHash.Write(certMsg.marshal())
   412  		c.writeRecord(recordTypeHandshake, certMsg.marshal())
   413  	}
   414  
   415  	preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
   416  	if err != nil {
   417  		c.sendAlert(alertInternalError)
   418  		return err
   419  	}
   420  	if ckx != nil {
   421  		hs.finishedHash.Write(ckx.marshal())
   422  		c.writeRecord(recordTypeHandshake, ckx.marshal())
   423  	}
   424  
   425  	if chainToSend != nil {
   426  		var signed []byte
   427  		certVerify := &certificateVerifyMsg{
   428  			hasSignatureAndHash: c.vers >= VersionTLS12,
   429  		}
   430  
   431  		key, ok := chainToSend.PrivateKey.(crypto.Signer)
   432  		if !ok {
   433  			c.sendAlert(alertInternalError)
   434  			return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
   435  		}
   436  		switch key.Public().(type) {
   437  		case *ecdsa.PublicKey:
   438  			digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureECDSA)
   439  			signed, err = key.Sign(c.config.rand(), digest, hashFunc)
   440  			certVerify.signatureAndHash.signature = signatureECDSA
   441  			certVerify.signatureAndHash.hash = hashId
   442  		case *rsa.PublicKey:
   443  			digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureRSA)
   444  			signed, err = key.Sign(c.config.rand(), digest, hashFunc)
   445  			certVerify.signatureAndHash.signature = signatureRSA
   446  			certVerify.signatureAndHash.hash = hashId
   447  		default:
   448  			err = fmt.Errorf("tls: unknown client certificate key type: %T", key)
   449  		}
   450  		if err != nil {
   451  			c.sendAlert(alertInternalError)
   452  			return errors.New("tls: failed to sign handshake with client certificate: " + err.Error())
   453  		}
   454  		certVerify.signature = signed
   455  
   456  		hs.finishedHash.Write(certVerify.marshal())
   457  		c.writeRecord(recordTypeHandshake, certVerify.marshal())
   458  	}
   459  
   460  	hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.hello.random, hs.serverHello.random)
   461  	return nil
   462  }
   463  
   464  func (hs *clientHandshakeState) establishKeys() error {
   465  	c := hs.c
   466  
   467  	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
   468  		keysFromMasterSecret(c.vers, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
   469  	var clientCipher, serverCipher interface{}
   470  	var clientHash, serverHash macFunction
   471  	if hs.suite.cipher != nil {
   472  		clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
   473  		clientHash = hs.suite.mac(c.vers, clientMAC)
   474  		serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
   475  		serverHash = hs.suite.mac(c.vers, serverMAC)
   476  	} else {
   477  		clientCipher = hs.suite.aead(clientKey, clientIV)
   478  		serverCipher = hs.suite.aead(serverKey, serverIV)
   479  	}
   480  
   481  	c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
   482  	c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
   483  	return nil
   484  }
   485  
   486  func (hs *clientHandshakeState) serverResumedSession() bool {
   487  	// If the server responded with the same sessionId then it means the
   488  	// sessionTicket is being used to resume a TLS session.
   489  	return hs.session != nil && hs.hello.sessionId != nil &&
   490  		bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
   491  }
   492  
   493  func (hs *clientHandshakeState) processServerHello() (bool, error) {
   494  	c := hs.c
   495  
   496  	if hs.serverHello.compressionMethod != compressionNone {
   497  		c.sendAlert(alertUnexpectedMessage)
   498  		return false, errors.New("tls: server selected unsupported compression format")
   499  	}
   500  
   501  	clientDidNPN := hs.hello.nextProtoNeg
   502  	clientDidALPN := len(hs.hello.alpnProtocols) > 0
   503  	serverHasNPN := hs.serverHello.nextProtoNeg
   504  	serverHasALPN := len(hs.serverHello.alpnProtocol) > 0
   505  
   506  	if !clientDidNPN && serverHasNPN {
   507  		c.sendAlert(alertHandshakeFailure)
   508  		return false, errors.New("server advertised unrequested NPN extension")
   509  	}
   510  
   511  	if !clientDidALPN && serverHasALPN {
   512  		c.sendAlert(alertHandshakeFailure)
   513  		return false, errors.New("server advertised unrequested ALPN extension")
   514  	}
   515  
   516  	if serverHasNPN && serverHasALPN {
   517  		c.sendAlert(alertHandshakeFailure)
   518  		return false, errors.New("server advertised both NPN and ALPN extensions")
   519  	}
   520  
   521  	if serverHasALPN {
   522  		c.clientProtocol = hs.serverHello.alpnProtocol
   523  		c.clientProtocolFallback = false
   524  	}
   525  
   526  	if hs.serverResumedSession() {
   527  		// Restore masterSecret and peerCerts from previous state
   528  		hs.masterSecret = hs.session.masterSecret
   529  		c.peerCertificates = hs.session.serverCertificates
   530  		return true, nil
   531  	}
   532  	return false, nil
   533  }
   534  
   535  func (hs *clientHandshakeState) readFinished(out []byte) error {
   536  	c := hs.c
   537  
   538  	c.readRecord(recordTypeChangeCipherSpec)
   539  	if err := c.in.error(); err != nil {
   540  		return err
   541  	}
   542  
   543  	msg, err := c.readHandshake()
   544  	if err != nil {
   545  		return err
   546  	}
   547  	serverFinished, ok := msg.(*finishedMsg)
   548  	if !ok {
   549  		c.sendAlert(alertUnexpectedMessage)
   550  		return unexpectedMessageError(serverFinished, msg)
   551  	}
   552  
   553  	verify := hs.finishedHash.serverSum(hs.masterSecret)
   554  	if len(verify) != len(serverFinished.verifyData) ||
   555  		subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
   556  		c.sendAlert(alertHandshakeFailure)
   557  		return errors.New("tls: server's Finished message was incorrect")
   558  	}
   559  	hs.finishedHash.Write(serverFinished.marshal())
   560  	copy(out, verify)
   561  	return nil
   562  }
   563  
   564  func (hs *clientHandshakeState) readSessionTicket() error {
   565  	if !hs.serverHello.ticketSupported {
   566  		return nil
   567  	}
   568  
   569  	c := hs.c
   570  	msg, err := c.readHandshake()
   571  	if err != nil {
   572  		return err
   573  	}
   574  	sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
   575  	if !ok {
   576  		c.sendAlert(alertUnexpectedMessage)
   577  		return unexpectedMessageError(sessionTicketMsg, msg)
   578  	}
   579  	hs.finishedHash.Write(sessionTicketMsg.marshal())
   580  
   581  	hs.session = &ClientSessionState{
   582  		sessionTicket:      sessionTicketMsg.ticket,
   583  		vers:               c.vers,
   584  		cipherSuite:        hs.suite.id,
   585  		masterSecret:       hs.masterSecret,
   586  		serverCertificates: c.peerCertificates,
   587  	}
   588  
   589  	return nil
   590  }
   591  
   592  func (hs *clientHandshakeState) sendFinished(out []byte) error {
   593  	c := hs.c
   594  
   595  	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
   596  	if hs.serverHello.nextProtoNeg {
   597  		nextProto := new(nextProtoMsg)
   598  		proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
   599  		nextProto.proto = proto
   600  		c.clientProtocol = proto
   601  		c.clientProtocolFallback = fallback
   602  
   603  		hs.finishedHash.Write(nextProto.marshal())
   604  		c.writeRecord(recordTypeHandshake, nextProto.marshal())
   605  	}
   606  
   607  	finished := new(finishedMsg)
   608  	finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
   609  	hs.finishedHash.Write(finished.marshal())
   610  	c.writeRecord(recordTypeHandshake, finished.marshal())
   611  	copy(out, finished.verifyData)
   612  	return nil
   613  }
   614  
   615  // clientSessionCacheKey returns a key used to cache sessionTickets that could
   616  // be used to resume previously negotiated TLS sessions with a server.
   617  func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
   618  	if len(config.ServerName) > 0 {
   619  		return config.ServerName
   620  	}
   621  	return serverAddr.String()
   622  }
   623  
   624  // mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol
   625  // given list of possible protocols and a list of the preference order. The
   626  // first list must not be empty. It returns the resulting protocol and flag
   627  // indicating if the fallback case was reached.
   628  func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
   629  	for _, s := range preferenceProtos {
   630  		for _, c := range protos {
   631  			if s == c {
   632  				return s, false
   633  			}
   634  		}
   635  	}
   636  
   637  	return protos[0], true
   638  }