gitee.com/lh-her-team/common@v1.5.1/crypto/tls/auto_handshake_server.go (about)

     1  package tls
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/ecdsa"
     6  	"crypto/rsa"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"sync/atomic"
    11  	"time"
    12  )
    13  
    14  // 服务服务端的混合握手
    15  // 根据客户端协议类型自动选择GMSSL协议或TLS系列协议
    16  func (c *Conn) serverHandshakeAutoSwitch() error {
    17  	// If this is the first server handshake, we generate a random key to
    18  	// encrypt the tickets with.
    19  	c.config.serverInitOnce.Do(func() { c.config.serverInit(nil) })
    20  	msg, err := c.readHandshake()
    21  	if err != nil {
    22  		return err
    23  	}
    24  	clientHello, ok := msg.(*clientHelloMsg)
    25  	if !ok {
    26  		_ = c.sendAlert(alertUnexpectedMessage)
    27  		return unexpectedMessageError("Client Hello Msg", msg)
    28  	}
    29  	//
    30  	// 根据客户端Hello消息的版本选择使用的
    31  	// GMSSL协议 或 TLS 协议
    32  	//
    33  	switch clientHello.vers {
    34  	case VersionGMSSL:
    35  		// 构造 国密SSL握手 状态上下文
    36  		hs := &serverHandshakeStateGM{
    37  			c:           c,
    38  			clientHello: clientHello,
    39  		}
    40  		// 处理读取到 客户端Hello 消息
    41  		isResume, err := processClientHelloGM(c, hs)
    42  		if err != nil {
    43  			return err
    44  		}
    45  		// 运行 GMSSL 握手流程
    46  		return runServerHandshakeGM(c, hs, isResume)
    47  	case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
    48  		// SSL v3.0 - TLS 1.3
    49  		// 构造 TLS 状态上下文
    50  		hs := &serverHandshakeState{
    51  			c:           c,
    52  			clientHello: clientHello,
    53  		}
    54  		// 处理读取到 客户端Hello 消息
    55  		isResume, err := processClientHello(c, hs)
    56  		if err != nil {
    57  			return err
    58  		}
    59  		// 运行 TLS 握手流程
    60  		return runServerHandshake(c, hs, isResume)
    61  	default:
    62  		_ = c.sendAlert(alertProtocolVersion)
    63  		return fmt.Errorf("tls: mix server handshake unsupport client protocol version: %X", clientHello.vers)
    64  	}
    65  }
    66  
    67  // 处理 GMSSL 客户端 Hello消息
    68  // Code segment copy from: gmtls/gm_handshake_server_double.go:114
    69  //
    70  // c: 连接对象
    71  // hs: GMSSL服务端握手状态
    72  //
    73  // return:
    74  // 			是否重用会话,true/false 重用/不重用
    75  //			错误信息
    76  func processClientHelloGM(c *Conn, hs *serverHandshakeStateGM) (isResume bool, err error) {
    77  	if c.config.GetConfigForClient != nil {
    78  		if newConfig, err := c.config.GetConfigForClient(hs.clientHelloInfo()); err != nil {
    79  			_ = c.sendAlert(alertInternalError)
    80  			return false, err
    81  		} else if newConfig != nil {
    82  			newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) })
    83  			c.config = newConfig
    84  		}
    85  	}
    86  	var ok bool
    87  	c.vers, ok = c.config.mutualVersion([]uint16{hs.clientHello.vers})
    88  	if !ok {
    89  		_ = c.sendAlert(alertProtocolVersion)
    90  		return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
    91  	}
    92  	c.haveVers = true
    93  	hs.hello = new(serverHelloMsg)
    94  	foundCompression := false
    95  	// We only support null compression, so check that the client offered it.
    96  	for _, compression := range hs.clientHello.compressionMethods {
    97  		if compression == compressionNone {
    98  			foundCompression = true
    99  			break
   100  		}
   101  	}
   102  	if !foundCompression {
   103  		_ = c.sendAlert(alertHandshakeFailure)
   104  		return false, errors.New("tls: client does not support uncompressed connections")
   105  	}
   106  	hs.hello.vers = c.vers
   107  	hs.hello.random = make([]byte, 32)
   108  	_, err = io.ReadFull(c.config.rand(), hs.hello.random)
   109  	if err != nil {
   110  		_ = c.sendAlert(alertInternalError)
   111  		return false, err
   112  	}
   113  	// Edit: 根据 GMT 0024 6.4.4.1.1 Client Hello 消息 b) random 描述
   114  	// 客户端产生的随机信息,其内容包括时钟和随机数。
   115  	gmtRandom(&(hs.hello.random))
   116  	if len(hs.clientHello.secureRenegotiation) != 0 {
   117  		_ = c.sendAlert(alertHandshakeFailure)
   118  		return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
   119  	}
   120  	hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
   121  	hs.hello.compressionMethod = compressionNone
   122  	if len(hs.clientHello.serverName) > 0 {
   123  		c.serverName = hs.clientHello.serverName
   124  	}
   125  	if len(hs.clientHello.alpnProtocols) > 0 {
   126  		if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
   127  			hs.hello.alpnProtocol = selectedProto
   128  			c.clientProtocol = selectedProto
   129  		}
   130  	}
   131  	// Edit:
   132  	//		通过获取证书方法获取 签名证书(含私钥)
   133  	//		通过获取证书方法获取 加密证书(含私钥)
   134  	sigCert, err := c.config.getCertificate(hs.clientHelloInfo())
   135  	if err != nil {
   136  		_ = c.sendAlert(alertInternalError)
   137  		return false, err
   138  	}
   139  	encCert, err := c.config.GetKECertificate(hs.clientHelloInfo())
   140  	if err != nil {
   141  		_ = c.sendAlert(alertInternalError)
   142  		return false, err
   143  	}
   144  	// GMT0024
   145  	if encCert == nil || sigCert == nil {
   146  		_ = c.sendAlert(alertInternalError)
   147  		return false, fmt.Errorf("tls: amount of server certificates must be greater than 2, which will sign and encipher respectively")
   148  	}
   149  	// 第1张证书为 签名证书、第2张为加密证书(用于密钥交换)
   150  	hs.cert = []Certificate{*sigCert, *encCert}
   151  	if hs.clientHello.scts {
   152  		hs.hello.scts = hs.cert[0].SignedCertificateTimestamps
   153  	}
   154  	if hs.checkForResumption() {
   155  		return true, nil
   156  	}
   157  	var preferenceList, supportedList []uint16
   158  	if c.config.PreferServerCipherSuites {
   159  		preferenceList = getCipherSuites(c.config)
   160  		supportedList = hs.clientHello.cipherSuites
   161  	} else {
   162  		preferenceList = hs.clientHello.cipherSuites
   163  		supportedList = getCipherSuites(c.config)
   164  	}
   165  	for _, id := range preferenceList {
   166  		if hs.setCipherSuite(id, supportedList, c.vers) {
   167  			break
   168  		}
   169  	}
   170  	if hs.suite == nil {
   171  		_ = c.sendAlert(alertHandshakeFailure)
   172  		return false, errors.New("tls: no cipher suite supported by both client and server")
   173  	}
   174  	// See https://tools.ietf.org/html/rfc7507.
   175  	for _, id := range hs.clientHello.cipherSuites {
   176  		if id == TLS_FALLBACK_SCSV {
   177  			// The client is doing a fallback connection.
   178  			if hs.clientHello.vers < c.config.maxVersion() {
   179  				_ = c.sendAlert(alertInappropriateFallback)
   180  				return false, errors.New("tls: client using inappropriate protocol fallback")
   181  			}
   182  			break
   183  		}
   184  	}
   185  	return false, nil
   186  }
   187  
   188  // 运行GMSSL服务端握手流程
   189  // Code segment copy from: gmtls/gm_handshake_server_double.go:39
   190  //
   191  // c: 连接对象
   192  // hs: GMSSL服务端握手状态
   193  // isResume: 是否重新启用会话
   194  //
   195  // return:
   196  //			错误信息
   197  func runServerHandshakeGM(c *Conn, hs *serverHandshakeStateGM, isResume bool) error {
   198  	// For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
   199  	c.buffering = true
   200  	if isResume {
   201  		// The client has included a session ticket and so we do an abbreviated handshake.
   202  		if err := hs.doResumeHandshake(); err != nil {
   203  			return err
   204  		}
   205  		if err := hs.establishKeys(); err != nil {
   206  			return err
   207  		}
   208  		// ticketSupported is set in a resumption handshake if the
   209  		// ticket from the client was encrypted with an old session
   210  		// ticket key and thus a refreshed ticket should be sent.
   211  		if hs.hello.ticketSupported {
   212  			if err := hs.sendSessionTicket(); err != nil {
   213  				return err
   214  			}
   215  		}
   216  		if err := hs.sendFinished(c.serverFinished[:]); err != nil {
   217  			return err
   218  		}
   219  		if _, err := c.flush(); err != nil {
   220  			return err
   221  		}
   222  		c.clientFinishedIsFirst = false
   223  		if err := hs.readFinished(nil); err != nil {
   224  			return err
   225  		}
   226  		c.didResume = true
   227  	} else {
   228  		// The client didn't include a session ticket, or it wasn't
   229  		// valid so we do a full handshake.
   230  		if err := hs.doFullHandshake(); err != nil {
   231  			return err
   232  		}
   233  		if err := hs.establishKeys(); err != nil {
   234  			return err
   235  		}
   236  		if err := hs.readFinished(c.clientFinished[:]); err != nil {
   237  			return err
   238  		}
   239  		c.clientFinishedIsFirst = true
   240  		c.buffering = true
   241  		if err := hs.sendSessionTicket(); err != nil {
   242  			return err
   243  		}
   244  		if err := hs.sendFinished(nil); err != nil {
   245  			return err
   246  		}
   247  		if _, err := c.flush(); err != nil {
   248  			return err
   249  		}
   250  	}
   251  
   252  	c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random)
   253  	atomic.StoreUint32(&c.handshakeStatus, 1)
   254  
   255  	return nil
   256  }
   257  
   258  // 处理 TLS 客户端 Hello消息
   259  // Code segment copy from: gmtls/handshake_server.go:122
   260  //
   261  // c: 连接对象
   262  // hs: TLS服务端握手状态
   263  //
   264  // return:
   265  // 			是否重用会话,true/false 重用/不重用
   266  //			错误信息
   267  func processClientHello(c *Conn, hs *serverHandshakeState) (bool, error) {
   268  	if c.config.GetConfigForClient != nil {
   269  		if newConfig, err := c.config.GetConfigForClient(hs.cachedClientHelloInfo); err != nil {
   270  			_ = c.sendAlert(alertInternalError)
   271  			return false, err
   272  		} else if newConfig != nil {
   273  			newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) })
   274  			c.config = newConfig
   275  		}
   276  	}
   277  	var ok bool
   278  	var err error
   279  	c.vers, ok = c.config.mutualVersion([]uint16{hs.clientHello.vers})
   280  	if !ok {
   281  		_ = c.sendAlert(alertProtocolVersion)
   282  		return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
   283  	}
   284  	c.haveVers = true
   285  
   286  	hs.hello = new(serverHelloMsg)
   287  
   288  	supportedCurve := false
   289  	preferredCurves := c.config.curvePreferences()
   290  Curves:
   291  	for _, curve := range hs.clientHello.supportedCurves {
   292  		for _, supported := range preferredCurves {
   293  			if supported == curve {
   294  				supportedCurve = true
   295  				break Curves
   296  			}
   297  		}
   298  	}
   299  
   300  	supportedPointFormat := false
   301  	for _, pointFormat := range hs.clientHello.supportedPoints {
   302  		if pointFormat == pointFormatUncompressed {
   303  			supportedPointFormat = true
   304  			break
   305  		}
   306  	}
   307  	hs.ecSignOk = supportedCurve && supportedPointFormat
   308  
   309  	foundCompression := false
   310  	// We only support null compression, so check that the client offered it.
   311  	for _, compression := range hs.clientHello.compressionMethods {
   312  		if compression == compressionNone {
   313  			foundCompression = true
   314  			break
   315  		}
   316  	}
   317  
   318  	if !foundCompression {
   319  		_ = c.sendAlert(alertHandshakeFailure)
   320  		return false, errors.New("tls: client does not support uncompressed connections")
   321  	}
   322  
   323  	hs.hello.vers = c.vers
   324  	hs.hello.random = make([]byte, 32)
   325  	_, err = io.ReadFull(c.config.rand(), hs.hello.random)
   326  	if err != nil {
   327  		_ = c.sendAlert(alertInternalError)
   328  		return false, err
   329  	}
   330  
   331  	if len(hs.clientHello.secureRenegotiation) != 0 {
   332  		_ = c.sendAlert(alertHandshakeFailure)
   333  		return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
   334  	}
   335  
   336  	hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
   337  	hs.hello.compressionMethod = compressionNone
   338  	if len(hs.clientHello.serverName) > 0 {
   339  		c.serverName = hs.clientHello.serverName
   340  	}
   341  
   342  	if len(hs.clientHello.alpnProtocols) > 0 {
   343  		if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
   344  			hs.hello.alpnProtocol = selectedProto
   345  			c.clientProtocol = selectedProto
   346  		}
   347  	}
   348  
   349  	hs.cert, err = c.config.getCertificate(hs.cachedClientHelloInfo)
   350  	if err != nil {
   351  		_ = c.sendAlert(alertInternalError)
   352  		return false, err
   353  	}
   354  	if hs.clientHello.scts {
   355  		hs.hello.scts = hs.cert.SignedCertificateTimestamps
   356  	}
   357  
   358  	if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
   359  		switch priv.Public().(type) {
   360  		case *ecdsa.PublicKey:
   361  			hs.ecSignOk = true
   362  		case *rsa.PublicKey:
   363  			hs.rsaSignOk = true
   364  		default:
   365  			_ = c.sendAlert(alertInternalError)
   366  			return false, fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
   367  		}
   368  	}
   369  	if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
   370  		switch priv.Public().(type) {
   371  		case *rsa.PublicKey:
   372  			hs.rsaDecryptOk = true
   373  		default:
   374  			_ = c.sendAlert(alertInternalError)
   375  			return false, fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
   376  		}
   377  	}
   378  
   379  	if hs.checkForResumption() {
   380  		return true, nil
   381  	}
   382  
   383  	if err = hs.pickCipherSuite(); err != nil {
   384  		_ = c.sendAlert(alertInternalError)
   385  		return false, err
   386  	}
   387  
   388  	if hs.suite == nil {
   389  		_ = c.sendAlert(alertHandshakeFailure)
   390  		return false, errors.New("tls: no cipher suite supported by both client and server")
   391  	}
   392  
   393  	// See https://tools.ietf.org/html/rfc7507.
   394  	for _, id := range hs.clientHello.cipherSuites {
   395  		if id == TLS_FALLBACK_SCSV {
   396  			// The client is doing a fallback connection.
   397  			if hs.clientHello.vers < c.config.maxVersion() {
   398  				_ = c.sendAlert(alertInappropriateFallback)
   399  				return false, errors.New("tls: client using inappropriate protocol fallback")
   400  			}
   401  			break
   402  		}
   403  	}
   404  
   405  	return false, nil
   406  }
   407  
   408  // 运行TLS服务端握手流程
   409  // Code segment copy from: gmtls/handshake_server.go:51
   410  //
   411  // c: 连接对象
   412  // hs: TLS服务端握手状态
   413  // isResume: 是否重新启用会话
   414  //
   415  // return:
   416  //			错误信息
   417  func runServerHandshake(c *Conn, hs *serverHandshakeState, isResume bool) error {
   418  	// For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
   419  	c.buffering = true
   420  	if isResume {
   421  		// The client has included a session ticket and so we do an abbreviated handshake.
   422  		if err := hs.doResumeHandshake(); err != nil {
   423  			return err
   424  		}
   425  		if err := hs.establishKeys(); err != nil {
   426  			return err
   427  		}
   428  		// ticketSupported is set in a resumption handshake if the
   429  		// ticket from the client was encrypted with an old session
   430  		// ticket key and thus a refreshed ticket should be sent.
   431  		if hs.hello.ticketSupported {
   432  			if err := hs.sendSessionTicket(); err != nil {
   433  				return err
   434  			}
   435  		}
   436  		if err := hs.sendFinished(c.serverFinished[:]); err != nil {
   437  			return err
   438  		}
   439  		if _, err := c.flush(); err != nil {
   440  			return err
   441  		}
   442  		c.clientFinishedIsFirst = false
   443  		if err := hs.readFinished(nil); err != nil {
   444  			return err
   445  		}
   446  		c.didResume = true
   447  	} else {
   448  		// The client didn't include a session ticket, or it wasn't
   449  		// valid so we do a full handshake.
   450  		if err := hs.doFullHandshake(); err != nil {
   451  			return err
   452  		}
   453  		if err := hs.establishKeys(); err != nil {
   454  			return err
   455  		}
   456  		if err := hs.readFinished(c.clientFinished[:]); err != nil {
   457  			return err
   458  		}
   459  		c.clientFinishedIsFirst = true
   460  		c.buffering = true
   461  		if err := hs.sendSessionTicket(); err != nil {
   462  			return err
   463  		}
   464  		if err := hs.sendFinished(nil); err != nil {
   465  			return err
   466  		}
   467  		if _, err := c.flush(); err != nil {
   468  			return err
   469  		}
   470  	}
   471  	c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random)
   472  	atomic.StoreUint32(&c.handshakeStatus, 1)
   473  	return nil
   474  }
   475  
   476  // 国密类型的随机数 4 byte unix time 28 byte random
   477  func gmtRandom(raw *[]byte) uint32 {
   478  	rd := *raw
   479  	unixTime := time.Now().Unix()
   480  	rd[0] = uint8(unixTime >> 24)
   481  	rd[1] = uint8(unixTime >> 16)
   482  	rd[2] = uint8(unixTime >> 8)
   483  	rd[3] = uint8(unixTime)
   484  	return uint32(unixTime)
   485  }