From b5c8c11c0c7350908eb3d6acac3fdcff0573daf5 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 11 Jan 2017 17:44:32 +0700 Subject: [PATCH] switch to forward-secure encryption after sending the SHLO --- benchmark_test.go | 1 + handshake/crypto_setup_server.go | 9 ++++++-- handshake/crypto_setup_server_test.go | 31 ++++++++++++++------------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/benchmark_test.go b/benchmark_test.go index 6b7bfd51..9319dee1 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -68,6 +68,7 @@ func (c *linkedConnection) Close() error { return nil } func setAEAD(cs handshake.CryptoSetup, aead crypto.AEAD) { *(*bool)(unsafe.Pointer(reflect.ValueOf(cs).Elem().FieldByName("receivedForwardSecurePacket").UnsafeAddr())) = true + *(*bool)(unsafe.Pointer(reflect.ValueOf(cs).Elem().FieldByName("sentSHLO").UnsafeAddr())) = true *(*crypto.AEAD)(unsafe.Pointer(reflect.ValueOf(cs).Elem().FieldByName("forwardSecureAEAD").UnsafeAddr())) = aead } diff --git a/handshake/crypto_setup_server.go b/handshake/crypto_setup_server.go index 33bf49c3..8bbd9262 100644 --- a/handshake/crypto_setup_server.go +++ b/handshake/crypto_setup_server.go @@ -31,6 +31,7 @@ type cryptoSetupServer struct { secureAEAD crypto.AEAD forwardSecureAEAD crypto.AEAD receivedForwardSecurePacket bool + sentSHLO bool receivedSecurePacket bool aeadChanged chan protocol.EncryptionLevel @@ -187,9 +188,12 @@ func (h *cryptoSetupServer) Open(dst, src []byte, packetNumber protocol.PacketNu // Seal a message, call LockForSealing() before! func (h *cryptoSetupServer) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel) { - if h.receivedForwardSecurePacket { + if h.forwardSecureAEAD != nil && h.sentSHLO { return h.forwardSecureAEAD.Seal(dst, src, packetNumber, associatedData), protocol.EncryptionForwardSecure } else if h.secureAEAD != nil { + // secureAEAD and forwardSecureAEAD are created at the same time (when receiving the CHLO) + // make sure that the SHLO isn't sent forward-secure + h.sentSHLO = true return h.secureAEAD.Seal(dst, src, packetNumber, associatedData), protocol.EncryptionSecure } else { return (&crypto.NullAEAD{}).Seal(dst, src, packetNumber, associatedData), protocol.EncryptionUnencrypted @@ -375,6 +379,7 @@ func (h *cryptoSetupServer) handleCHLO(sni string, data []byte, cryptoData map[T replyMap[TagSNO] = serverNonce replyMap[TagVER] = protocol.SupportedVersionsAsTags + // note that the SHLO *has* to fit into one packet var reply bytes.Buffer WriteHandshakeMessage(&reply, TagSHLO, replyMap) utils.Debugf("Sending SHLO:\n%s", printHandshakeMessage(replyMap)) @@ -386,7 +391,7 @@ func (h *cryptoSetupServer) handleCHLO(sni string, data []byte, cryptoData map[T // DiversificationNonce returns a diversification nonce if required in the next packet to be Seal'ed. See LockForSealing()! func (h *cryptoSetupServer) DiversificationNonce() []byte { - if h.receivedForwardSecurePacket || h.secureAEAD == nil { + if h.secureAEAD == nil || h.sentSHLO { return nil } return h.diversificationNonce diff --git a/handshake/crypto_setup_server_test.go b/handshake/crypto_setup_server_test.go index 6232a151..89b22ee9 100644 --- a/handshake/crypto_setup_server_test.go +++ b/handshake/crypto_setup_server_test.go @@ -194,8 +194,8 @@ var _ = Describe("Crypto setup", func() { Expect(cs.DiversificationNonce()).To(HaveLen(32)) }) - It("does not return nonce for FS packets", func() { - cs.receivedForwardSecurePacket = true + It("does not return nonce after sending the SHLO", func() { + cs.sentSHLO = true Expect(cs.DiversificationNonce()).To(BeEmpty()) }) @@ -633,15 +633,6 @@ var _ = Describe("Crypto setup", func() { Expect(d).To(Equal([]byte("decrypted"))) }) - It("is not used after receiving forward secure packet", func() { - doCHLO() - _, _, err := cs.Open(nil, []byte("forward secure encrypted"), 0, []byte{}) - Expect(err).ToNot(HaveOccurred()) - d, enc := cs.Seal(nil, []byte("foobar"), 0, []byte{}) - Expect(d).To(Equal([]byte("foobar forward sec"))) - Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) - }) - It("is not accepted after receiving forward secure packet", func() { doCHLO() _, _, err := cs.Open(nil, []byte("forward secure encrypted"), 0, []byte{}) @@ -653,15 +644,25 @@ var _ = Describe("Crypto setup", func() { }) Context("forward secure encryption", func() { - It("is used after receiving forward secure packet", func() { + It("is used after sending out one packet with initial encryption", func() { doCHLO() - _, enc, err := cs.Open(nil, []byte("forward secure encrypted"), 0, []byte{}) - Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) - Expect(err).ToNot(HaveOccurred()) + _, enc := cs.Seal(nil, []byte("SHLO"), 0, []byte{}) + Expect(enc).To(Equal(protocol.EncryptionSecure)) d, enc := cs.Seal(nil, []byte("foobar"), 0, []byte{}) Expect(d).To(Equal([]byte("foobar forward sec"))) Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) }) + + It("regards the handshake as complete once it receives a forward encrypted packet", func() { + doCHLO() + _, enc := cs.Seal(nil, []byte("SHLO"), 0, []byte{}) + Expect(enc).To(Equal(protocol.EncryptionSecure)) + _, enc = cs.Seal(nil, []byte("foobar"), 0, []byte{}) + Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) + Expect(cs.HandshakeComplete()).To(BeFalse()) + cs.receivedForwardSecurePacket = true + Expect(cs.HandshakeComplete()).To(BeTrue()) + }) }) Context("forcing encryption levels", func() {