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
}
|