File: cfsslscan_handshake.go

package info (click to toggle)
golang-github-cloudflare-cfssl 1.2.0%2Bgit20160825.89.7fb22c8-3.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bookworm-proposed-updates, bullseye
  • size: 4,916 kB
  • sloc: javascript: 635; sh: 146; sql: 62; python: 11; makefile: 8
file content (109 lines) | stat: -rw-r--r-- 3,224 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package tls

// SayHello constructs a simple Client Hello to a server, parses its serverHelloMsg response
// and returns the negotiated ciphersuite ID, and, if an EC cipher suite, the curve ID
func (c *Conn) SayHello(newSigAls []SignatureAndHash) (cipherID, curveType uint16, curveID CurveID, version uint16, certs [][]byte, err error) {
	// Set the supported signatures and hashes to the set `newSigAls`
	supportedSignatureAlgorithms := make([]signatureAndHash, len(newSigAls))
	for i := range newSigAls {
		supportedSignatureAlgorithms[i] = newSigAls[i].internal()
	}

	hello := &clientHelloMsg{
		vers:                c.config.maxVersion(),
		compressionMethods:  []uint8{compressionNone},
		random:              make([]byte, 32),
		ocspStapling:        true,
		serverName:          c.config.ServerName,
		supportedCurves:     c.config.curvePreferences(),
		supportedPoints:     []uint8{pointFormatUncompressed},
		nextProtoNeg:        len(c.config.NextProtos) > 0,
		secureRenegotiation: true,
		cipherSuites:        c.config.cipherSuites(),
		signatureAndHashes:  supportedSignatureAlgorithms,
	}
	serverHello, err := c.sayHello(hello)
	if err != nil {
		return
	}
	// Prime the connection, if necessary, for key
	// exchange messages by reading off the certificate
	// message and, if necessary, the OCSP stapling
	// message
	var msg interface{}
	msg, err = c.readHandshake()
	if err != nil {
		return
	}
	certMsg, ok := msg.(*certificateMsg)
	if !ok || len(certMsg.certificates) == 0 {
		err = unexpectedMessageError(certMsg, msg)
		return
	}
	certs = certMsg.certificates

	if serverHello.ocspStapling {
		msg, err = c.readHandshake()
		if err != nil {
			return
		}
		certStatusMsg, ok := msg.(*certificateStatusMsg)
		if !ok {
			err = unexpectedMessageError(certStatusMsg, msg)
			return
		}
	}

	if CipherSuites[serverHello.cipherSuite].EllipticCurve {

		var skx *serverKeyExchangeMsg
		skx, err = c.exchangeKeys()
		if err != nil {
			return
		}
		if skx.raw[0] != typeServerKeyExchange {
			err = unexpectedMessageError(skx, msg)
			return
		}
		if len(skx.key) < 4 {
			err = unexpectedMessageError(skx, msg)
			return
		}
		curveType = uint16(skx.key[0])
		// If we have a named curve, report which one it is.
		if curveType == 3 {
			curveID = CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
		}
	}
	cipherID, version = serverHello.cipherSuite, serverHello.vers

	return
}

// sayHello is the backend to SayHello that returns a full serverHelloMsg for processing.
func (c *Conn) sayHello(hello *clientHelloMsg) (serverHello *serverHelloMsg, err error) {
	c.writeRecord(recordTypeHandshake, hello.marshal())
	msg, err := c.readHandshake()
	if err != nil {
		return
	}
	serverHello, ok := msg.(*serverHelloMsg)
	if !ok {
		return nil, unexpectedMessageError(serverHello, msg)
	}
	return
}

// exchangeKeys continues the handshake to receive the serverKeyExchange message,
// from which we can extract elliptic curve parameters
func (c *Conn) exchangeKeys() (serverKeyExchange *serverKeyExchangeMsg, err error) {
	msg, err := c.readHandshake()
	if err != nil {
		return
	}
	serverKeyExchange, ok := msg.(*serverKeyExchangeMsg)
	if !ok {
		return nil, unexpectedMessageError(serverKeyExchange, msg)
	}
	return
}