mirror of
https://github.com/golang/go
synced 2024-11-25 07:07:57 -07:00
crypto/tls: extend NPN support to the client.
R=bradfitzgo, rsc1, bradfitzwork CC=golang-dev https://golang.org/cl/4277085
This commit is contained in:
parent
d844aae690
commit
974d2c98e0
@ -93,9 +93,10 @@ const (
|
|||||||
|
|
||||||
// ConnectionState records basic TLS details about the connection.
|
// ConnectionState records basic TLS details about the connection.
|
||||||
type ConnectionState struct {
|
type ConnectionState struct {
|
||||||
HandshakeComplete bool
|
HandshakeComplete bool
|
||||||
CipherSuite uint16
|
CipherSuite uint16
|
||||||
NegotiatedProtocol string
|
NegotiatedProtocol string
|
||||||
|
NegotiatedProtocolIsMutual bool
|
||||||
|
|
||||||
// the certificate chain that was presented by the other side
|
// the certificate chain that was presented by the other side
|
||||||
PeerCertificates []*x509.Certificate
|
PeerCertificates []*x509.Certificate
|
||||||
@ -124,7 +125,6 @@ type Config struct {
|
|||||||
RootCAs *CASet
|
RootCAs *CASet
|
||||||
|
|
||||||
// NextProtos is a list of supported, application level protocols.
|
// NextProtos is a list of supported, application level protocols.
|
||||||
// Currently only server-side handling is supported.
|
|
||||||
NextProtos []string
|
NextProtos []string
|
||||||
|
|
||||||
// ServerName is included in the client's handshake to support virtual
|
// ServerName is included in the client's handshake to support virtual
|
||||||
|
@ -35,7 +35,8 @@ type Conn struct {
|
|||||||
ocspResponse []byte // stapled OCSP response
|
ocspResponse []byte // stapled OCSP response
|
||||||
peerCertificates []*x509.Certificate
|
peerCertificates []*x509.Certificate
|
||||||
|
|
||||||
clientProtocol string
|
clientProtocol string
|
||||||
|
clientProtocolFallback bool
|
||||||
|
|
||||||
// first permanent error
|
// first permanent error
|
||||||
errMutex sync.Mutex
|
errMutex sync.Mutex
|
||||||
@ -761,6 +762,7 @@ func (c *Conn) ConnectionState() ConnectionState {
|
|||||||
state.HandshakeComplete = c.handshakeComplete
|
state.HandshakeComplete = c.handshakeComplete
|
||||||
if c.handshakeComplete {
|
if c.handshakeComplete {
|
||||||
state.NegotiatedProtocol = c.clientProtocol
|
state.NegotiatedProtocol = c.clientProtocol
|
||||||
|
state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
|
||||||
state.CipherSuite = c.cipherSuite
|
state.CipherSuite = c.cipherSuite
|
||||||
state.PeerCertificates = c.peerCertificates
|
state.PeerCertificates = c.peerCertificates
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ func (c *Conn) clientHandshake() os.Error {
|
|||||||
serverName: c.config.ServerName,
|
serverName: c.config.ServerName,
|
||||||
supportedCurves: []uint16{curveP256, curveP384, curveP521},
|
supportedCurves: []uint16{curveP256, curveP384, curveP521},
|
||||||
supportedPoints: []uint8{pointFormatUncompressed},
|
supportedPoints: []uint8{pointFormatUncompressed},
|
||||||
|
nextProtoNeg: len(c.config.NextProtos) > 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
t := uint32(c.config.time())
|
t := uint32(c.config.time())
|
||||||
@ -66,6 +67,11 @@ func (c *Conn) clientHandshake() os.Error {
|
|||||||
return c.sendAlert(alertUnexpectedMessage)
|
return c.sendAlert(alertUnexpectedMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !hello.nextProtoNeg && serverHello.nextProtoNeg {
|
||||||
|
c.sendAlert(alertHandshakeFailure)
|
||||||
|
return os.ErrorString("server advertised unrequested NPN")
|
||||||
|
}
|
||||||
|
|
||||||
suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
|
suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
|
||||||
if suite == nil {
|
if suite == nil {
|
||||||
return c.sendAlert(alertHandshakeFailure)
|
return c.sendAlert(alertHandshakeFailure)
|
||||||
@ -267,6 +273,17 @@ func (c *Conn) clientHandshake() os.Error {
|
|||||||
c.out.prepareCipherSpec(clientCipher, clientHash)
|
c.out.prepareCipherSpec(clientCipher, clientHash)
|
||||||
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
||||||
|
|
||||||
|
if serverHello.nextProtoNeg {
|
||||||
|
nextProto := new(nextProtoMsg)
|
||||||
|
proto, fallback := mutualProtocol(c.config.NextProtos, serverHello.nextProtos)
|
||||||
|
nextProto.proto = proto
|
||||||
|
c.clientProtocol = proto
|
||||||
|
c.clientProtocolFallback = fallback
|
||||||
|
|
||||||
|
finishedHash.Write(nextProto.marshal())
|
||||||
|
c.writeRecord(recordTypeHandshake, nextProto.marshal())
|
||||||
|
}
|
||||||
|
|
||||||
finished := new(finishedMsg)
|
finished := new(finishedMsg)
|
||||||
finished.verifyData = finishedHash.clientSum(masterSecret)
|
finished.verifyData = finishedHash.clientSum(masterSecret)
|
||||||
finishedHash.Write(finished.marshal())
|
finishedHash.Write(finished.marshal())
|
||||||
@ -299,3 +316,19 @@ func (c *Conn) clientHandshake() os.Error {
|
|||||||
c.cipherSuite = suiteId
|
c.cipherSuite = suiteId
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mutualProtocol finds the mutual Next Protocol Negotiation protocol given the
|
||||||
|
// set of client and server supported protocols. The set of client supported
|
||||||
|
// protocols must not be empty. It returns the resulting protocol and flag
|
||||||
|
// indicating if the fallback case was reached.
|
||||||
|
func mutualProtocol(clientProtos, serverProtos []string) (string, bool) {
|
||||||
|
for _, s := range serverProtos {
|
||||||
|
for _, c := range clientProtos {
|
||||||
|
if s == c {
|
||||||
|
return s, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientProtos[0], true
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user