diff --git a/handshake/server_config_client.go b/handshake/server_config_client.go index 1c99d0be..e3ee4f7d 100644 --- a/handshake/server_config_client.go +++ b/handshake/server_config_client.go @@ -57,7 +57,6 @@ func (s *serverConfigClient) parseValues(tagMap map[Tag][]byte) error { s.ID = scfgID // KEXS - // TODO: allow for P256 in the list // TODO: setup Key Exchange kexs, ok := tagMap[TagKEXS] if !ok { @@ -66,8 +65,16 @@ func (s *serverConfigClient) parseValues(tagMap map[Tag][]byte) error { if len(kexs)%4 != 0 { return qerr.Error(qerr.CryptoInvalidValueLength, "KEXS") } - if !bytes.Equal(kexs, []byte("C255")) { - return qerr.Error(qerr.CryptoNoSupport, "KEXS") + c255Foundat := -1 + + for i := 0; i < len(kexs)/4; i++ { + if bytes.Equal(kexs[4*i:4*i+4], []byte("C255")) { + c255Foundat = i + break + } + } + if c255Foundat < 0 { + return qerr.Error(qerr.CryptoNoSupport, "KEXS: Could not find C255, other key exchanges are not supported") } // AEAD @@ -90,12 +97,37 @@ func (s *serverConfigClient) parseValues(tagMap map[Tag][]byte) error { } // PUBS - // TODO: save this value pubs, ok := tagMap[TagPUBS] if !ok { return qerr.Error(qerr.CryptoMessageParameterNotFound, "PUBS") } - if len(pubs) != 35 { + + var pubs_kexs []struct{Length uint32; Value []byte} + var last_len uint32 + + for i := 0; i < len(pubs)-3; i += int(last_len)+3 { + // the PUBS value is always prepended by 3 byte little endian length field + + err := binary.Read(bytes.NewReader([]byte{pubs[i], pubs[i+1], pubs[i+2], 0x00}), binary.LittleEndian, &last_len); + if err != nil { + return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS not decodable") + } + if last_len == 0 { + return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS") + } + + if i+3+int(last_len) > len(pubs) { + return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS") + } + + pubs_kexs = append(pubs_kexs, struct{Length uint32; Value []byte}{last_len, pubs[i+3:i+3+int(last_len)]}) + } + + if c255Foundat >= len(pubs_kexs) { + return qerr.Error(qerr.CryptoMessageParameterNotFound, "KEXS not in PUBS") + } + + if pubs_kexs[c255Foundat].Length != 32 { return qerr.Error(qerr.CryptoInvalidValueLength, "PUBS") } @@ -105,8 +137,8 @@ func (s *serverConfigClient) parseValues(tagMap map[Tag][]byte) error { return err } - // the PUBS value is always prepended by []byte{0x20, 0x00, 0x00} - s.sharedSecret, err = s.kex.CalculateSharedKey(pubs[3:]) + + s.sharedSecret, err = s.kex.CalculateSharedKey(pubs_kexs[c255Foundat].Value) if err != nil { return err } diff --git a/handshake/server_config_client_test.go b/handshake/server_config_client_test.go index 34d314ab..509c6bba 100644 --- a/handshake/server_config_client_test.go +++ b/handshake/server_config_client_test.go @@ -15,7 +15,7 @@ func getDefaultServerConfigClient() map[Tag][]byte { TagSCID: bytes.Repeat([]byte{'F'}, 16), TagKEXS: []byte("C255"), TagAEAD: []byte("AESG"), - TagPUBS: bytes.Repeat([]byte{0}, 35), + TagPUBS: append([]byte{0x20, 0x00, 0x00}, bytes.Repeat([]byte{0}, 32)...), TagOBIT: bytes.Repeat([]byte{0}, 8), TagEXPY: []byte{0x0, 0x6c, 0x57, 0x78, 0, 0, 0, 0}, // 2033-12-24 } @@ -124,7 +124,7 @@ var _ = Describe("Server Config", func() { It("rejects KEXS values other than C255", func() { tagMap[TagKEXS] = []byte("P256") err := scfg.parseValues(tagMap) - Expect(err).To(MatchError("CryptoNoSupport: KEXS")) + Expect(err).To(MatchError("CryptoNoSupport: KEXS: Could not find C255, other key exchanges are not supported")) }) It("errors if the KEXS is missing", func() { @@ -184,6 +184,25 @@ var _ = Describe("Server Config", func() { Expect(err).To(MatchError("CryptoInvalidValueLength: PUBS")) }) + It("rejects PUBS values that have a zero length", func() { + tagMap[TagPUBS] = bytes.Repeat([]byte{0}, 100) // completely wrong length + err := scfg.parseValues(tagMap) + Expect(err).To(MatchError("CryptoInvalidValueLength: PUBS")) + }) + + It("ensure that C255 Pubs must not be at the first index", func() { + serverKex, err := crypto.NewCurve25519KEX() + Expect(err).ToNot(HaveOccurred()) + tagMap[TagKEXS] = []byte("P256C255") // have another KEXS before C255 + // 3 byte len + 1 byte empty + C255 + tagMap[TagPUBS] = append([]byte{0x01, 0x00, 0x00, 0x00}, append([]byte{0x20, 0x00, 0x00}, serverKex.PublicKey()...)...) + err = scfg.parseValues(tagMap) + Expect(err).ToNot(HaveOccurred()) + sharedSecret, err := serverKex.CalculateSharedKey(scfg.kex.PublicKey()) + Expect(err).ToNot(HaveOccurred()) + Expect(scfg.sharedSecret).To(Equal(sharedSecret)) + }) + It("errors if the PUBS is missing", func() { delete(tagMap, TagPUBS) err := scfg.parseValues(tagMap)