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 }