forked from quic-go/quic-go
fix client handshake failure when the server supports unknown versions
This commit is contained in:
@@ -283,24 +283,21 @@ func (h *cryptoSetupClient) handleSHLOMessage(cryptoData map[Tag][]byte) (*Trans
|
||||
}
|
||||
|
||||
func (h *cryptoSetupClient) validateVersionList(verTags []byte) bool {
|
||||
if len(h.negotiatedVersions) == 0 {
|
||||
numNegotiatedVersions := len(h.negotiatedVersions)
|
||||
if numNegotiatedVersions == 0 {
|
||||
return true
|
||||
}
|
||||
if len(verTags)%4 != 0 || len(verTags)/4 != len(h.negotiatedVersions) {
|
||||
if len(verTags)%4 != 0 || len(verTags)/4 != numNegotiatedVersions {
|
||||
return false
|
||||
}
|
||||
|
||||
b := bytes.NewReader(verTags)
|
||||
for _, negotiatedVersion := range h.negotiatedVersions {
|
||||
verTag, err := utils.BigEndian.ReadUint32(b)
|
||||
for i := 0; i < numNegotiatedVersions; i++ {
|
||||
v, err := utils.BigEndian.ReadUint32(b)
|
||||
if err != nil { // should never occur, since the length was already checked
|
||||
return false
|
||||
}
|
||||
ver := protocol.VersionNumber(verTag)
|
||||
if !protocol.IsSupportedVersion(protocol.SupportedVersions, ver) {
|
||||
ver = protocol.VersionUnsupported
|
||||
}
|
||||
if ver != negotiatedVersion {
|
||||
if protocol.VersionNumber(v) != h.negotiatedVersions[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,9 +194,9 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
Expect(cs.validateVersionList([]byte{0})).To(BeTrue())
|
||||
})
|
||||
|
||||
It("detects a downgrade attack if the number of versions is unequal", func() {
|
||||
It("detects a downgrade attack if the number of versions is not equal", func() {
|
||||
cs.negotiatedVersions = []protocol.VersionNumber{protocol.VersionWhatever}
|
||||
Expect(cs.validateVersionList(bytes.Repeat([]byte{'f'}, 8))).To(BeFalse())
|
||||
Expect(cs.validateVersionList(bytes.Repeat([]byte{'f'}, 2*4))).To(BeFalse())
|
||||
})
|
||||
|
||||
It("detects a downgrade attack", func() {
|
||||
@@ -208,17 +208,7 @@ var _ = Describe("Client Crypto Setup", func() {
|
||||
|
||||
It("errors if the version tags are invalid", func() {
|
||||
cs.negotiatedVersions = []protocol.VersionNumber{protocol.VersionWhatever}
|
||||
Expect(cs.validateVersionList([]byte{0, 1, 2})).To(BeFalse())
|
||||
})
|
||||
|
||||
It("doesn't care about unsupported versions", func() {
|
||||
ver := protocol.SupportedVersions[0]
|
||||
cs.negotiatedVersions = []protocol.VersionNumber{protocol.VersionUnsupported, ver, protocol.VersionUnsupported}
|
||||
b := &bytes.Buffer{}
|
||||
b.Write([]byte{0, 0, 0, 0})
|
||||
utils.BigEndian.WriteUint32(b, uint32(ver))
|
||||
b.Write([]byte{0x13, 0x37, 0x13, 0x37})
|
||||
Expect(cs.validateVersionList(b.Bytes())).To(BeTrue())
|
||||
Expect(cs.validateVersionList([]byte{0, 1, 2})).To(BeFalse()) // 1 byte too short
|
||||
})
|
||||
|
||||
It("returns the right error when detecting a downgrade attack", func() {
|
||||
|
||||
@@ -89,8 +89,11 @@ func (h *extensionHandlerClient) Receive(hType mint.HandshakeType, el *mint.Exte
|
||||
return qerr.Error(qerr.VersionNegotiationMismatch, "current version not included in the supported versions")
|
||||
}
|
||||
// if version negotiation was performed, check that we would have selected the current version based on the supported versions sent by the server
|
||||
if h.version != h.initialVersion && h.version != protocol.ChooseSupportedVersion(h.supportedVersions, serverSupportedVersions) {
|
||||
return qerr.Error(qerr.VersionNegotiationMismatch, "would have picked a different version")
|
||||
if h.version != h.initialVersion {
|
||||
negotiatedVersion, ok := protocol.ChooseSupportedVersion(h.supportedVersions, serverSupportedVersions)
|
||||
if !ok || h.version != negotiatedVersion {
|
||||
return qerr.Error(qerr.VersionNegotiationMismatch, "would have picked a different version")
|
||||
}
|
||||
}
|
||||
|
||||
// check that the server sent the stateless reset token
|
||||
|
||||
@@ -167,7 +167,9 @@ var _ = Describe("TLS Extension Handler, for the client", func() {
|
||||
handler.supportedVersions = []protocol.VersionNumber{43, 42, 41}
|
||||
serverSupportedVersions := []protocol.VersionNumber{42, 43}
|
||||
// check that version negotiation would have led us to pick version 43
|
||||
Expect(protocol.ChooseSupportedVersion(handler.supportedVersions, serverSupportedVersions)).To(Equal(protocol.VersionNumber(43)))
|
||||
ver, ok := protocol.ChooseSupportedVersion(handler.supportedVersions, serverSupportedVersions)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(ver).To(Equal(protocol.VersionNumber(43)))
|
||||
ssv := make([]uint32, len(serverSupportedVersions))
|
||||
for i, v := range serverSupportedVersions {
|
||||
ssv[i] = uint32(v)
|
||||
@@ -188,7 +190,9 @@ var _ = Describe("TLS Extension Handler, for the client", func() {
|
||||
handler.supportedVersions = []protocol.VersionNumber{43, 42, 41}
|
||||
serverSupportedVersions := []protocol.VersionNumber{42, 43}
|
||||
// check that version negotiation would have led us to pick version 43
|
||||
Expect(protocol.ChooseSupportedVersion(handler.supportedVersions, serverSupportedVersions)).To(Equal(protocol.VersionNumber(43)))
|
||||
ver, ok := protocol.ChooseSupportedVersion(handler.supportedVersions, serverSupportedVersions)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(ver).To(Equal(protocol.VersionNumber(43)))
|
||||
ssv := make([]uint32, len(serverSupportedVersions))
|
||||
for i, v := range serverSupportedVersions {
|
||||
ssv[i] = uint32(v)
|
||||
|
||||
Reference in New Issue
Block a user