go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/network/resources/tlsshake/tlsshake.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 // shake that SSL 5 6 package tlsshake 7 8 import ( 9 "bufio" 10 "bytes" 11 "crypto/x509" 12 "encoding/binary" 13 "encoding/hex" 14 "errors" 15 "io" 16 "math/rand" 17 "net" 18 "net/http" 19 "strconv" 20 "sync" 21 "time" 22 23 "go.mondoo.com/cnquery/utils/multierr" 24 "golang.org/x/crypto/ocsp" 25 ) 26 27 var TLS_VERSIONS = []string{"ssl3", "tls1.0", "tls1.1", "tls1.2", "tls1.3"} 28 29 // ScanConfig allows to tune the TLS scanner 30 type ScanConfig struct { 31 Versions []string 32 SNIsupported bool 33 FakeSNI bool 34 SecureClientRenegotiation bool 35 36 // internal scan fields that users don't configure 37 version string 38 ciphersFilter func(string) bool 39 } 40 41 func DefaultScanConfig() ScanConfig { 42 return ScanConfig{ 43 SNIsupported: true, 44 FakeSNI: true, 45 SecureClientRenegotiation: true, 46 } 47 } 48 49 // Tester is the test runner and results object for any findings done in a 50 // session of tests. We re-use it to avoid duplicate requests and optimize 51 // the overall test run. 52 type Tester struct { 53 Findings Findings 54 sync sync.Mutex 55 proto string 56 target string 57 domainName string 58 } 59 60 // Findings tracks the current state of tested components and their findings 61 type Findings struct { 62 Versions map[string]bool 63 Ciphers map[string]bool 64 Extensions map[string]bool 65 Errors []string 66 Certificates []*x509.Certificate 67 NonSNIcertificates []*x509.Certificate 68 Revocations map[string]*revocation 69 } 70 71 type revocation struct { 72 At time.Time 73 Via string 74 Reason int 75 } 76 77 // New creates a new tester object for the given target (via proto, host, port) 78 // - the proto, host, and port are used to construct the target for net.Dial 79 // example: proto="tcp", host="mondoo.io", port=443 80 func New(proto string, domainName string, host string, port int) *Tester { 81 target := host + ":" + strconv.Itoa(port) 82 83 return &Tester{ 84 Findings: Findings{ 85 Versions: map[string]bool{}, 86 Ciphers: map[string]bool{}, 87 Extensions: map[string]bool{}, 88 Revocations: map[string]*revocation{}, 89 }, 90 proto: proto, 91 target: target, 92 domainName: domainName, 93 } 94 } 95 96 // Test runs the TLS/SSL probes for a given scan configuration 97 // - versions may contain any supported pre-defined TLS/SSL versions 98 // with a complete list found in TLS_VERSIONS. Leave empty to test all. 99 func (s *Tester) Test(conf ScanConfig) error { 100 if len(conf.Versions) == 0 { 101 conf.Versions = TLS_VERSIONS 102 } 103 104 workers := sync.WaitGroup{} 105 var errs multierr.Errors 106 107 remainingCiphers := func(cipher string) bool { 108 s.sync.Lock() 109 defer s.sync.Unlock() 110 if v, ok := s.Findings.Ciphers[cipher]; ok && v { 111 return false 112 } 113 return true 114 } 115 supportedCiphers := func(cipher string) bool { 116 s.sync.Lock() 117 defer s.sync.Unlock() 118 if v, ok := s.Findings.Ciphers[cipher]; ok && v { 119 return true 120 } 121 return false 122 } 123 124 for i := range conf.Versions { 125 version := conf.Versions[i] 126 127 workers.Add(1) 128 go func() { 129 defer workers.Done() 130 131 // we don't activate any of the additional tests in the beginning 132 // let's find out if we work on this version of TLS/SSL 133 curConf := &ScanConfig{ 134 version: version, 135 ciphersFilter: remainingCiphers, 136 } 137 138 for { 139 remaining, err := s.testTLS(s.proto, s.target, curConf) 140 if err != nil { 141 s.sync.Lock() 142 errs.Add(err) 143 s.sync.Unlock() 144 return 145 } 146 147 if remaining <= 0 { 148 break 149 } 150 } 151 152 if version == "tls1.2" || version == "tls1.3" { 153 if conf.SNIsupported || conf.SecureClientRenegotiation { 154 curConf = &ScanConfig{ 155 version: version, 156 ciphersFilter: supportedCiphers, 157 SNIsupported: conf.SNIsupported, 158 SecureClientRenegotiation: conf.SecureClientRenegotiation, 159 } 160 s.testTLS(s.proto, s.target, curConf) 161 } 162 163 if conf.FakeSNI { 164 curConf = &ScanConfig{ 165 version: version, 166 ciphersFilter: supportedCiphers, 167 FakeSNI: conf.FakeSNI, 168 } 169 s.testTLS(s.proto, s.target, curConf) 170 } 171 } 172 }() 173 } 174 175 workers.Wait() 176 177 return errs.Deduplicate() 178 } 179 180 // Attempts to connect to an endpoint with a given version and records 181 // results in the Tester. 182 // Returns the number of remaining ciphers to test (if so desired) 183 // and any potential error 184 func (s *Tester) testTLS(proto string, target string, conf *ScanConfig) (int, error) { 185 conn, err := net.Dial(proto, target) 186 if err != nil { 187 return 0, multierr.Wrap(err, "failed to connect to target") 188 } 189 defer conn.Close() 190 191 msg, cipherCount, err := s.helloTLSMsg(conf) 192 if err != nil { 193 return 0, err 194 } 195 196 _, err = conn.Write(msg) 197 if err != nil { 198 return 0, multierr.Wrap(err, "failed to send TLS hello") 199 } 200 201 success, err := s.parseHello(conn, conf) 202 if err != nil || !success { 203 return 0, err 204 } 205 206 return cipherCount - 1, nil 207 } 208 209 func (s *Tester) addError(msg string) { 210 s.sync.Lock() 211 s.Findings.Errors = append(s.Findings.Errors, msg) 212 s.sync.Unlock() 213 } 214 215 func (s *Tester) parseAlert(data []byte, conf *ScanConfig) error { 216 var severity string 217 switch data[0] { 218 case '\x01': 219 severity = "Warning" 220 case '\x02': 221 severity = "Fatal" 222 default: 223 severity = "Unknown" 224 } 225 226 description, ok := ALERT_DESCRIPTIONS[data[1]] 227 if !ok { 228 description = "cannot find description" 229 } 230 231 switch description { 232 case "PROTOCOL_VERSION": 233 // here we know the TLS version is not supported 234 s.sync.Lock() 235 s.Findings.Versions[conf.version] = false 236 s.sync.Unlock() 237 238 case "HANDSHAKE_FAILURE": 239 if conf.version == "ssl3" { 240 // Note: it's a little fuzzy here, since we don't know if the protocol 241 // version is unsupported or just its ciphers. So we check if we found 242 // it previously and if so, don't add it to the list of unsupported 243 // versions. 244 if _, ok := s.Findings.Versions["ssl3"]; !ok { 245 s.sync.Lock() 246 s.Findings.Versions["ssl3"] = false 247 s.sync.Unlock() 248 } 249 } 250 251 names := cipherNames(conf.version, conf.ciphersFilter) 252 for i := range names { 253 name := names[i] 254 if _, ok := s.Findings.Ciphers[name]; !ok { 255 s.sync.Lock() 256 s.Findings.Ciphers[name] = false 257 s.sync.Unlock() 258 } 259 } 260 261 default: 262 s.addError("failed to connect via " + conf.version + ": " + severity + " - " + description) 263 } 264 265 return nil 266 } 267 268 func (s *Tester) parseServerHello(data []byte, version string, conf *ScanConfig) error { 269 idx := 0 270 271 idx += 2 + 32 272 // handshake tls version (2), which we don't need yet (we will look at it in the extension if necessary) 273 // random (32), which we don't need 274 275 // we don't need the session ID 276 sessionIDlen := byte1int(data[idx]) 277 idx += 1 278 idx += sessionIDlen 279 280 cipher, cipherOK := ALL_CIPHERS[string(data[idx:idx+2])] 281 idx += 2 282 283 // TLS 1.3 pretends to be TLS 1.2 in the preceding headers for 284 // compatibility. To correctly identify it, we have to look at 285 // any Supported Versions extensions that the server sent us. 286 287 // compression method (which should be set to null) 288 idx += 1 289 290 // no extensions found 291 var allExtLen int 292 if len(data) >= idx+2 { 293 allExtLen = bytes2int(data[idx : idx+2]) 294 idx += 2 295 } 296 297 for allExtLen > 0 && idx < len(data) { 298 extType := string(data[idx : idx+2]) 299 extLen := bytes2int(data[idx+2 : idx+4]) 300 extData := string(data[idx+4 : idx+4+extLen]) 301 302 allExtLen -= 4 + extLen 303 idx += 4 + extLen 304 305 switch extType { 306 case EXTENSION_SupportedVersions: 307 if v, ok := VERSIONS_LOOKUP[extData]; ok { 308 version = v 309 } else { 310 s.Findings.Errors = append(s.Findings.Errors, "Failed to parse supported_versions extension: '"+extData+"'") 311 } 312 case EXTENSION_RenegotiationInfo: 313 s.Findings.Extensions["renegotiation_info"] = true 314 } 315 } 316 317 // we have to wait for any changes to the detected version (in the extensions) 318 // once done, let's lock it once and write all results 319 s.sync.Lock() 320 if !cipherOK { 321 s.Findings.Ciphers["unknown"] = true 322 } else { 323 s.Findings.Ciphers[cipher] = true 324 } 325 s.Findings.Versions[version] = true 326 s.sync.Unlock() 327 328 return nil 329 } 330 331 func (s *Tester) parseCertificate(data []byte, conf *ScanConfig) error { 332 certsLen := bytes3int(data[0:3]) 333 if len(data) < certsLen+3 { 334 return errors.New("malformed certificate response, too little data read from stream to parse certificate") 335 } 336 337 certs := []*x509.Certificate{} 338 i := 3 339 for i < 3+certsLen { 340 certLen := bytes3int(data[i : i+3]) 341 i += 3 342 343 rawCert := data[i : i+certLen] 344 i += certLen 345 346 cert, err := x509.ParseCertificate(rawCert) 347 if err != nil { 348 s.addError( 349 multierr.Wrap(err, "failed to parse certificate (x509 parser error)").Error(), 350 ) 351 } else { 352 certs = append(certs, cert) 353 } 354 } 355 356 // TODO: we are currently overwriting any certs that may have been tested already 357 // The assumption is that the same endpoint will always return the same 358 // certificates no matter what version/configuration is used. 359 // This may not be true and in case it isn't improve this code to carefully 360 // write new certificates and manage separate certificate chains 361 s.sync.Lock() 362 if conf.SNIsupported { 363 // by default we collect with SNI enabled. If the test is set to test SNI, 364 // we actually test the exact opposite, ie what do we get without SNI. 365 // Thus, we collect the non-sni certificates here 366 s.Findings.NonSNIcertificates = certs 367 368 if len(certs) != 0 && len(s.Findings.Certificates) != 0 { 369 if !bytes.Equal(certs[0].Raw, s.Findings.Certificates[0].Raw) { 370 s.Findings.Extensions["server_name"] = true 371 } 372 } 373 } else if conf.FakeSNI { 374 if len(certs) != 0 && len(s.Findings.NonSNIcertificates) != 0 { 375 if bytes.Equal(certs[0].Raw, s.Findings.NonSNIcertificates[0].Raw) { 376 s.Findings.Extensions["fake_server_name"] = true 377 } 378 } 379 } else { 380 s.Findings.Certificates = certs 381 } 382 s.sync.Unlock() 383 384 for i := 0; i+1 < len(certs); i++ { 385 err := s.ocspRequest(certs[i], certs[i+1]) 386 if err != nil { 387 s.addError(err.Error()) 388 } 389 } 390 391 return nil 392 } 393 394 // returns true if we are done parsing through handshake responses. 395 // - If i'ts a ServerHello, it will check if we have certificates. 396 // If we don't, we should read more handshake responses... 397 // If we do, we might as well be done at this stage, no need to read more 398 // - There are a few other responses that also signal that we are done 399 // processing handshake responses, like ServerHelloDone or Finished 400 func (s *Tester) parseHandshake(data []byte, version string, conf *ScanConfig) (bool, error) { 401 handshakeType := data[0] 402 handshakeLen := bytes3int(data[1:4]) 403 404 switch handshakeType { 405 case HANDSHAKE_TYPE_ServerHello: 406 err := s.parseServerHello(data[4:4+handshakeLen], version, conf) 407 return false, err 408 case HANDSHAKE_TYPE_Certificate: 409 return true, s.parseCertificate(data[4:4+handshakeLen], conf) 410 case HANDSHAKE_TYPE_ServerKeyExchange: 411 return false, nil 412 case HANDSHAKE_TYPE_ServerHelloDone: 413 return true, nil 414 case HANDSHAKE_TYPE_Finished: 415 return true, nil 416 default: 417 typ := "0x" + hex.EncodeToString([]byte{handshakeType}) 418 s.addError("Unhandled TLS/SSL handshake: '" + typ + "'") 419 return false, nil 420 } 421 } 422 423 // returns: 424 // 425 // true if the handshake was successful, false otherwise 426 func (s *Tester) parseHello(conn net.Conn, conf *ScanConfig) (bool, error) { 427 reader := bufio.NewReader(conn) 428 header := make([]byte, 5) 429 var success bool 430 var done bool 431 432 for !done { 433 _, err := io.ReadFull(reader, header) 434 if err != nil { 435 if err == io.EOF { 436 break 437 } 438 return false, err 439 } 440 441 typ := "0x" + hex.EncodeToString(header[0:1]) 442 headerVersion := VERSIONS_LOOKUP[string(header[1:3])] 443 444 msgLen := bytes2int(header[3:5]) 445 if msgLen == 0 { 446 return false, errors.New("No body in TLS/SSL response (type: '" + typ + "')") 447 } 448 if msgLen > 1<<20 { 449 return false, errors.New("TLS/SSL response body is too larget (type: '" + typ + "')") 450 } 451 452 msg := make([]byte, msgLen) 453 _, err = io.ReadFull(reader, msg) 454 if err != nil { 455 return false, multierr.Wrap(err, "Failed to read full TLS/SSL response body (type: '"+typ+"')") 456 } 457 458 switch header[0] { 459 case CONTENT_TYPE_Alert: 460 // Do not grab the version here, instead use the pre-provided 461 // There is a nice edge-case in TLS1.3 which is handled further down, 462 // but not required here since we are dealing with an error 463 if err := s.parseAlert(msg, conf); err != nil { 464 return false, err 465 } 466 467 case CONTENT_TYPE_Handshake: 468 handshakeDone, err := s.parseHandshake(msg, headerVersion, conf) 469 if err != nil { 470 return false, err 471 } 472 success = true 473 done = handshakeDone 474 475 case CONTENT_TYPE_ChangeCipherSpec: 476 // This also means we are done with this stream, since it signals that we 477 // are no longer looking at a handshake. 478 done = true 479 480 case CONTENT_TYPE_Application: 481 // Definitely don't care about anything past the handshake. 482 done = true 483 484 default: 485 s.addError("Unhandled TLS/SSL response (received '" + typ + "')") 486 } 487 } 488 489 return success, nil 490 } 491 492 func filterCipherMsg(org map[string]string, f func(cipher string) bool) ([]byte, int) { 493 var res bytes.Buffer 494 var n int 495 for k, v := range org { 496 if f(v) { 497 res.WriteString(k) 498 n++ 499 } 500 } 501 return res.Bytes(), n 502 } 503 504 func filterCipherNames(org map[string]string, f func(cipher string) bool) []string { 505 var res []string 506 for _, v := range org { 507 if f(v) { 508 res = append(res, v) 509 } 510 } 511 return res 512 } 513 514 func cipherNames(version string, filter func(cipher string) bool) []string { 515 switch version { 516 case "ssl3": 517 regular := filterCipherNames(SSL3_CIPHERS, filter) 518 fips := filterCipherNames(SSL_FIPS_CIPHERS, filter) 519 return append(regular, fips...) 520 case "tls1.0", "tls1.1", "tls1.2": 521 return filterCipherNames(TLS_CIPHERS, filter) 522 case "tls1.3": 523 return filterCipherNames(TLS13_CIPHERS, filter) 524 default: 525 return []string{} 526 } 527 } 528 529 func writeExtension(buf *bytes.Buffer, typ string, body []byte) { 530 buf.WriteString(typ) 531 buf.Write(int2bytes(len(body))) 532 buf.Write(body) 533 } 534 535 func sniMsg(domainName string) []byte { 536 l := len(domainName) 537 var res bytes.Buffer 538 539 res.Write(int2bytes(l + 3)) // server name list length 540 res.WriteByte('\x00') // name type: host name 541 res.Write(int2bytes(l)) // name length 542 res.WriteString(domainName) // name 543 544 return res.Bytes() 545 } 546 547 func (s *Tester) helloTLSMsg(conf *ScanConfig) ([]byte, int, error) { 548 var ciphers []byte 549 var cipherCount int 550 551 var extensions bytes.Buffer 552 553 if conf.version != "ssl3" { 554 domainName := s.domainName 555 if conf.SNIsupported { 556 // don't write an SNI and see if we get a different certificates 557 domainName = "" 558 } else if conf.FakeSNI { 559 // give it a fake name 560 domainName = strconv.FormatUint(rand.Uint64(), 10) + ".com" 561 } 562 563 if domainName != "" { 564 writeExtension(&extensions, EXTENSION_ServerName, sniMsg(domainName)) 565 } 566 567 // add signature_algorithms 568 extensions.WriteString("\x00\x0d\x00\x14\x00\x12\x04\x03\x08\x04\x04\x01\x05\x03\x08\x05\x05\x01\x08\x06\x06\x01\x02\x01") 569 } 570 571 if conf.version == "tls1.2" || conf.version == "tls1.3" { 572 // Renegotiation info 573 // https://datatracker.ietf.org/doc/html/rfc5746 574 // - we leave the body empty, we only need a response to the request 575 // - the body has 1 byte containing the length of the extension (which is 0) 576 if conf.SecureClientRenegotiation { 577 writeExtension(&extensions, EXTENSION_RenegotiationInfo, []byte("\x00")) 578 } 579 } 580 581 switch conf.version { 582 case "ssl3": 583 regular, n1 := filterCipherMsg(SSL3_CIPHERS, conf.ciphersFilter) 584 fips, n2 := filterCipherMsg(SSL_FIPS_CIPHERS, conf.ciphersFilter) 585 ciphers = append(regular, fips...) 586 cipherCount = n1 + n2 587 588 case "tls1.0", "tls1.1", "tls1.2": 589 org, n1 := filterCipherMsg(TLS10_CIPHERS, conf.ciphersFilter) 590 tls, n2 := filterCipherMsg(TLS_CIPHERS, conf.ciphersFilter) 591 ciphers = append(org, tls...) 592 cipherCount = n1 + n2 593 594 // add heartbeat 595 extensions.WriteString("\x00\x0f\x00\x01\x01") 596 // add ec_points_format 597 extensions.WriteString("\x00\x0b\x00\x02\x01\x00") 598 // add elliptic_curve 599 extensions.WriteString("\x00\x0a\x00\x0a\x00\x08\xfa\xfa\x00\x1d\x00\x17\x00\x18") 600 601 case "tls1.3": 602 org, n1 := filterCipherMsg(TLS10_CIPHERS, conf.ciphersFilter) 603 tls, n2 := filterCipherMsg(TLS_CIPHERS, conf.ciphersFilter) 604 tls13, n3 := filterCipherMsg(TLS13_CIPHERS, conf.ciphersFilter) 605 ciphers = append(org, tls...) 606 ciphers = append(ciphers, tls13...) 607 cipherCount = n1 + n2 + n3 608 609 // TLSv1.3 Supported Versions extension 610 extensions.WriteString("\x00\x2b\x00\x03\x02\x03\x04") 611 // add supported groups extension 612 extensions.WriteString("\x00\x0a\x00\x08\x00\x06\x00\x1d\x00\x17\x00\x18") 613 614 // This is a pre-generated public/private key pair using the x25519 curve: 615 // It was generated from the command line with: 616 // 617 // > openssl-1.1.1e/apps/openssl genpkey -algorithm x25519 > pkey 618 // > openssl-1.1.1e/apps/openssl pkey -noout -text < pkey 619 // priv: 620 // 30:90:f3:89:f4:9e:52:59:3c:ba:e9:f4:78:84:a0: 621 // 23:86:73:5e:f5:c9:46:6c:3a:c3:4e:ec:56:57:81: 622 // 5d:62 623 // pub: 624 // e7:08:71:36:d0:81:e0:16:19:3a:cb:67:ca:b8:28: 625 // d9:45:92:16:ff:36:63:0d:0d:5a:3d:9d:47:ce:3e: 626 // cd:7e 627 628 publicKey := "\xe7\x08\x71\x36\xd0\x81\xe0\x16\x19\x3a\xcb\x67\xca\xb8\x28\xd9\x45\x92\x16\xff\x36\x63\x0d\x0d\x5a\x3d\x9d\x47\xce\x3e\xcd\x7e" 629 extensions.WriteString("\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20") 630 extensions.WriteString(publicKey) 631 632 default: 633 return nil, 0, errors.New("unsupported TLS/SSL version: " + conf.version) 634 } 635 636 return constructTLSHello(conf.version, ciphers, extensions.Bytes()), cipherCount, nil 637 } 638 639 // OCSP: 640 // https://datatracker.ietf.org/doc/html/rfc6960 641 // https://datatracker.ietf.org/doc/html/rfc2560 642 643 func (s *Tester) ocspRequest(cert *x509.Certificate, issuer *x509.Certificate) error { 644 if len(cert.OCSPServer) == 0 { 645 return errors.New("no OCSP server specified for revocation check, skipping it") 646 } 647 648 server := cert.OCSPServer[0] 649 650 req, err := ocsp.CreateRequest(cert, issuer, &ocsp.RequestOptions{}) 651 if err != nil { 652 return multierr.Wrap(err, "failed to create OCSP request") 653 } 654 655 reqBody := bytes.NewBuffer(req) 656 res, err := http.Post(server, "application/ocsp-request", reqBody) 657 if err != nil { 658 return multierr.Wrap(err, "failed to post OCSP request") 659 } 660 661 if res.StatusCode != 200 { 662 return errors.New("OCSP request returned " + res.Status) 663 } 664 resp, err := io.ReadAll(res.Body) 665 if err != nil { 666 return multierr.Wrap(err, "failed to read OCSP response") 667 } 668 ocspRes, err := ocsp.ParseResponseForCert(resp, cert, issuer) 669 if err != nil { 670 return multierr.Wrap(err, "failed to parse OCSP response") 671 } 672 673 s.sync.Lock() 674 if ocspRes.RevokedAt.IsZero() { 675 s.Findings.Revocations[string(cert.Signature)] = nil 676 } else { 677 s.Findings.Revocations[string(cert.Signature)] = &revocation{ 678 At: ocspRes.RevokedAt, 679 Via: server, 680 Reason: ocspRes.RevocationReason, 681 } 682 } 683 s.sync.Unlock() 684 685 return nil 686 } 687 688 func int1byte(i int) []byte { 689 res := make([]byte, 2) 690 binary.BigEndian.PutUint16(res, uint16(i)) 691 return res[1:] 692 } 693 694 func int2bytes(i int) []byte { 695 res := make([]byte, 2) 696 binary.BigEndian.PutUint16(res, uint16(i)) 697 return res 698 } 699 700 func int3bytes(i int) []byte { 701 res := make([]byte, 4) 702 binary.BigEndian.PutUint32(res, uint32(i)) 703 return res[1:] 704 } 705 706 func byte1int(b byte) int { 707 return int(binary.BigEndian.Uint16([]byte{0x00, b})) 708 } 709 710 func bytes2int(b []byte) int { 711 return int(binary.BigEndian.Uint16(b)) 712 } 713 714 func bytes3int(b []byte) int { 715 return int(binary.BigEndian.Uint32(append([]byte{0x00}, b...))) 716 } 717 718 func constructTLSHello(version string, ciphers []byte, extensions []byte) []byte { 719 sessionID := "" 720 compressions := "\x00" 721 722 var content bytes.Buffer 723 content.WriteString(VERSIONS[version]) 724 725 rnd := make([]byte, 8) 726 binary.BigEndian.PutUint64(rnd, rand.Uint64()) 727 content.Write(rnd) 728 binary.BigEndian.PutUint64(rnd, rand.Uint64()) 729 content.Write(rnd) 730 binary.BigEndian.PutUint64(rnd, rand.Uint64()) 731 content.Write(rnd) 732 binary.BigEndian.PutUint64(rnd, rand.Uint64()) 733 content.Write(rnd) 734 735 content.Write(int1byte(len(sessionID))) 736 content.WriteString(sessionID) 737 738 content.Write(int2bytes(len(ciphers))) 739 content.Write(ciphers) 740 741 content.Write(int1byte(len(compressions))) 742 content.WriteString(compressions) 743 744 content.Write(int2bytes(len(extensions))) 745 content.Write(extensions) 746 747 c := content.Bytes() 748 749 core := []byte{HANDSHAKE_TYPE_ClientHello} 750 core = append(core, int3bytes(len(c))...) 751 core = append(core, c...) 752 753 return constructTLSMsg(CONTENT_TYPE_Handshake, core, []byte(VERSIONS[version])) 754 } 755 756 func constructTLSMsg(contentType byte, content []byte, version []byte) []byte { 757 var res bytes.Buffer 758 res.WriteByte(contentType) 759 res.Write(version) 760 res.Write(int2bytes(len(content))) 761 res.Write(content) 762 return res.Bytes() 763 } 764 765 var VERSIONS = map[string]string{ 766 "ssl3": "\x03\x00", 767 "tls1.0": "\x03\x01", 768 "tls1.1": "\x03\x02", 769 "tls1.2": "\x03\x03", 770 // RFC 8446 4.1.2: 771 // In TLS 1.3, the client indicates its version preferences in the 772 // "supported_versions" extension (Section 4.2.1) and the 773 // legacy_version field MUST be set to 0x0303, which is the version 774 // number for TLS 1.2. TLS 1.3 ClientHellos are identified as having 775 // a legacy_version of 0x0303 and a supported_versions extension 776 // present with 0x0304 as the highest version indicated therein. 777 "tls1.3": "\x03\x04", 778 } 779 780 var ( 781 VERSIONS_LOOKUP map[string]string 782 ALL_CIPHERS map[string]string 783 ) 784 785 func init() { 786 VERSIONS_LOOKUP = make(map[string]string, len(VERSIONS)) 787 for k, v := range VERSIONS { 788 VERSIONS_LOOKUP[v] = k 789 } 790 791 ALL_CIPHERS = make(map[string]string, 792 len(SSL2_CIPHERS)+ 793 len(SSL_FIPS_CIPHERS)+ 794 len(TLS10_CIPHERS)+ 795 len(TLS13_CIPHERS)+ 796 len(TLS_CIPHERS)) 797 798 // Note: overlapping names will be overwritten 799 for k, v := range SSL2_CIPHERS { 800 ALL_CIPHERS[k] = v 801 } 802 for k, v := range SSL3_CIPHERS { 803 ALL_CIPHERS[k] = v 804 } 805 for k, v := range SSL_FIPS_CIPHERS { 806 ALL_CIPHERS[k] = v 807 } 808 for k, v := range TLS10_CIPHERS { 809 ALL_CIPHERS[k] = v 810 } 811 for k, v := range TLS13_CIPHERS { 812 ALL_CIPHERS[k] = v 813 } 814 for k, v := range TLS_CIPHERS { 815 ALL_CIPHERS[k] = v 816 } 817 } 818 819 const ( 820 CONTENT_TYPE_ChangeCipherSpec byte = '\x14' 821 CONTENT_TYPE_Alert byte = '\x15' 822 CONTENT_TYPE_Handshake byte = '\x16' 823 CONTENT_TYPE_Application byte = '\x17' 824 CONTENT_TYPE_Heartbeat byte = '\x18' 825 826 HANDSHAKE_TYPE_HelloRequest byte = '\x00' 827 HANDSHAKE_TYPE_ClientHello byte = '\x01' 828 HANDSHAKE_TYPE_ServerHello byte = '\x02' 829 HANDSHAKE_TYPE_NewSessionTicket byte = '\x04' 830 HANDSHAKE_TYPE_Certificate byte = '\x0b' 831 HANDSHAKE_TYPE_ServerKeyExchange byte = '\x0c' 832 HANDSHAKE_TYPE_CertificateRequest byte = '\x0d' 833 HANDSHAKE_TYPE_ServerHelloDone byte = '\x0e' 834 HANDSHAKE_TYPE_CertificateVerify byte = '\x0f' 835 HANDSHAKE_TYPE_ClientKeyExchange byte = '\x10' 836 HANDSHAKE_TYPE_Finished byte = '\x14' 837 838 EXTENSION_ServerName string = "\x00\x00" 839 EXTENSION_SupportedVersions string = "\x00\x2b" 840 EXTENSION_RenegotiationInfo string = "\xff\x01" 841 ) 842 843 // https://tools.ietf.org/html/rfc5246#appendix-A.3 844 // https://tools.ietf.org/html/rfc8446#appendix-B.2 845 var ALERT_DESCRIPTIONS = map[byte]string{ 846 '\x00': "CLOSE_NOTIFY", 847 '\x0A': "UNEXPECTED_MESSAGE", 848 '\x14': "BAD_RECORD_MAC", 849 '\x15': "DECRYPTION_FAILED_RESERVED", 850 '\x16': "RECORD_OVERFLOW", 851 '\x1E': "DECOMPRESSION_FAILURE", 852 '\x28': "HANDSHAKE_FAILURE", 853 '\x29': "NO_CERTIFICATE_RESERVED", 854 '\x2A': "BAD_CERTIFICATE", 855 '\x2B': "UNSUPPORTED_CERTIFICATE", 856 '\x2C': "CERTIFICATE_REVOKED", 857 '\x2D': "CERTIFICATE_EXPIRED", 858 '\x2E': "CERTIFICATE_UNKNOWN", 859 '\x2F': "ILLEGAL_PARAMETER", 860 '\x30': "UNKNOWN_CA", 861 '\x31': "ACCESS_DENIED", 862 '\x32': "DECODE_ERROR", 863 '\x33': "DECRYPT_ERROR", 864 '\x3C': "EXPORT_RESTRICTION_RESERVED", 865 '\x46': "PROTOCOL_VERSION", 866 '\x47': "INSUFFICIENT_SECURITY", 867 '\x50': "INTERNAL_ERROR", 868 '\x56': "INAPPROPRIATE_FALLBACK", 869 '\x5A': "USER_CANCELED", 870 '\x64': "NO_RENEGOTIATION_RESERVED", 871 '\x6D': "MISSING_EXTENSION", 872 '\x6E': "UNSUPPORTED_EXTENSION", 873 '\x6F': "CERTIFICATE_UNOBTAINABLE_RESERVED", 874 '\x70': "UNRECOGNIZED_NAME", 875 '\x71': "BAD_CERTIFICATE_STATUS_RESPONSE", 876 '\x72': "BAD_CERTIFICATE_HASH_VALUE_RESERVED", 877 '\x73': "UNKNOWN_PSK_IDENTITY", 878 '\x74': "CERTIFICATE_REQUIRED", 879 '\x78': "NO_APPLICATION_PROTOCOL", 880 }