fix client handshake failure when the server supports unknown versions

This commit is contained in:
Marten Seemann
2017-11-02 17:08:06 +07:00
parent 1f6f5bb736
commit 43c23ff5fa
8 changed files with 59 additions and 49 deletions

View File

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

View File

@@ -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() {

View File

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

View File

@@ -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)