diff --git a/Changelog.md b/Changelog.md index fe92d7b3..cbf56a81 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,7 +9,7 @@ - Use a varint for error codes. - Add support for [quic-trace](https://github.com/google/quic-trace). - Add a context to `Listener.Accept`, `Session.Accept{Uni}Stream` and `Session.Open{Uni}StreamSync`. -- Implement receiving of TLS key updates. +- Implement TLS key updates. ## v0.11.0 (2019-04-05) diff --git a/integrationtests/self/key_update_test.go b/integrationtests/self/key_update_test.go new file mode 100644 index 00000000..975337a7 --- /dev/null +++ b/integrationtests/self/key_update_test.go @@ -0,0 +1,57 @@ +package self_test + +import ( + "context" + "fmt" + "io/ioutil" + "net" + "os" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Key Update tests", func() { + var server quic.Listener + + runServer := func() { + var err error + // start the server + server, err = quic.ListenAddr("localhost:0", getTLSConfig(), nil) + Expect(err).ToNot(HaveOccurred()) + + go func() { + defer GinkgoRecover() + sess, err := server.Accept(context.Background()) + Expect(err).ToNot(HaveOccurred()) + str, err := sess.OpenUniStream() + Expect(err).ToNot(HaveOccurred()) + defer str.Close() + _, err = str.Write(testserver.PRDataLong) + Expect(err).ToNot(HaveOccurred()) + }() + } + + BeforeEach(func() { + // update keys as frequently as possible + os.Setenv("QUIC_GO_KEY_UPDATE_INTERVAL", "1") + runServer() + }) + + It("downloads a large file", func() { + sess, err := quic.DialAddr( + fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), + getTLSClientConfig(), + nil, + ) + Expect(err).ToNot(HaveOccurred()) + defer sess.Close() + str, err := sess.AcceptUniStream(context.Background()) + Expect(err).ToNot(HaveOccurred()) + data, err := ioutil.ReadAll(str) + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal(testserver.PRDataLong)) + }) +}) diff --git a/internal/handshake/crypto_setup.go b/internal/handshake/crypto_setup.go index 1fe6c340..509c13c3 100644 --- a/internal/handshake/crypto_setup.go +++ b/internal/handshake/crypto_setup.go @@ -223,7 +223,8 @@ func (h *cryptoSetup) ChangeConnectionID(id protocol.ConnectionID) error { return nil } -func (h *cryptoSetup) Received1RTTAck() { +func (h *cryptoSetup) SetLargest1RTTAcked(pn protocol.PacketNumber) { + h.aead.SetLargestAcked(pn) // drop initial keys // TODO: do this earlier if h.initialOpener != nil { diff --git a/internal/handshake/interface.go b/internal/handshake/interface.go index 07152c1f..55bc035d 100644 --- a/internal/handshake/interface.go +++ b/internal/handshake/interface.go @@ -71,7 +71,7 @@ type CryptoSetup interface { ChangeConnectionID(protocol.ConnectionID) error HandleMessage([]byte, protocol.EncryptionLevel) bool - Received1RTTAck() + SetLargest1RTTAcked(protocol.PacketNumber) ConnectionState() tls.ConnectionState GetInitialOpener() (LongHeaderOpener, error) diff --git a/internal/handshake/updatable_aead.go b/internal/handshake/updatable_aead.go index 0967b373..4fe8767b 100644 --- a/internal/handshake/updatable_aead.go +++ b/internal/handshake/updatable_aead.go @@ -4,6 +4,9 @@ import ( "crypto" "crypto/cipher" "encoding/binary" + "fmt" + "os" + "strconv" "github.com/lucas-clemente/quic-go/internal/qerr" "github.com/lucas-clemente/quic-go/internal/utils" @@ -12,15 +15,44 @@ import ( "github.com/marten-seemann/qtls" ) +// By setting this environment variable, the key update interval can be adjusted. +// This is not needed in production, but useful for integration and interop testing. +// Note that no mattter what value is set, a key update is only initiated once it is +// permitted (i.e. once an ACK for a packet sent at the current key phase has been received). +const keyUpdateEnv = "QUIC_GO_KEY_UPDATE_INTERVAL" + +var keyUpdateInterval uint64 + +func init() { + setKeyUpdateInterval() +} + +func setKeyUpdateInterval() { + env := os.Getenv(keyUpdateEnv) + if env == "" { + keyUpdateInterval = protocol.KeyUpdateInterval + return + } + interval, err := strconv.ParseUint(env, 10, 64) + if err != nil { + panic(fmt.Sprintf("Cannot parse %s: %s", keyUpdateEnv, err)) + } + keyUpdateInterval = interval +} + type updatableAEAD struct { suite cipherSuite - keyPhase protocol.KeyPhase + keyPhase protocol.KeyPhase + largestAcked protocol.PacketNumber + keyUpdateInterval uint64 prevRcvAEAD cipher.AEAD firstRcvdWithCurrentKey protocol.PacketNumber firstSentWithCurrentKey protocol.PacketNumber + numRcvdWithCurrentKey uint64 + numSentWithCurrentKey uint64 rcvAEAD cipher.AEAD sendAEAD cipher.AEAD @@ -44,17 +76,20 @@ var _ ShortHeaderSealer = &updatableAEAD{} func newUpdatableAEAD(logger utils.Logger) *updatableAEAD { return &updatableAEAD{ + largestAcked: protocol.InvalidPacketNumber, firstRcvdWithCurrentKey: protocol.InvalidPacketNumber, firstSentWithCurrentKey: protocol.InvalidPacketNumber, + keyUpdateInterval: keyUpdateInterval, logger: logger, } } func (a *updatableAEAD) rollKeys() { a.keyPhase = a.keyPhase.Next() - a.logger.Debugf("Updating keys to the next key phase: %s", a.keyPhase) a.firstRcvdWithCurrentKey = protocol.InvalidPacketNumber a.firstSentWithCurrentKey = protocol.InvalidPacketNumber + a.numRcvdWithCurrentKey = 0 + a.numSentWithCurrentKey = 0 a.prevRcvAEAD = a.rcvAEAD a.rcvAEAD = a.nextRcvAEAD a.sendAEAD = a.nextSendAEAD @@ -126,6 +161,7 @@ func (a *updatableAEAD) Open(dst, src []byte, pn protocol.PacketNumber, kp proto return nil, qerr.Error(qerr.ProtocolViolation, "keys updated too quickly") } a.rollKeys() + a.logger.Debugf("Peer updated keys to %s", a.keyPhase) a.firstRcvdWithCurrentKey = pn return dec, err } @@ -134,8 +170,11 @@ func (a *updatableAEAD) Open(dst, src []byte, pn protocol.PacketNumber, kp proto dec, err := a.rcvAEAD.Open(dst, a.nonceBuf, src, ad) if err != nil { err = ErrDecryptionFailed - } else if a.firstRcvdWithCurrentKey == protocol.InvalidPacketNumber { - a.firstRcvdWithCurrentKey = pn + } else { + a.numRcvdWithCurrentKey++ + if a.firstRcvdWithCurrentKey == protocol.InvalidPacketNumber { + a.firstRcvdWithCurrentKey = pn + } } return dec, err } @@ -144,13 +183,42 @@ func (a *updatableAEAD) Seal(dst, src []byte, pn protocol.PacketNumber, ad []byt if a.firstSentWithCurrentKey == protocol.InvalidPacketNumber { a.firstSentWithCurrentKey = pn } + a.numSentWithCurrentKey++ binary.BigEndian.PutUint64(a.nonceBuf[len(a.nonceBuf)-8:], uint64(pn)) // The AEAD we're using here will be the qtls.aeadAESGCM13. // It uses the nonce provided here and XOR it with the IV. return a.sendAEAD.Seal(dst, a.nonceBuf, src, ad) } +func (a *updatableAEAD) SetLargestAcked(pn protocol.PacketNumber) { + a.largestAcked = pn +} + +func (a *updatableAEAD) updateAllowed() bool { + return a.firstSentWithCurrentKey != protocol.InvalidPacketNumber && + a.largestAcked != protocol.InvalidPacketNumber && + a.largestAcked >= a.firstSentWithCurrentKey +} + +func (a *updatableAEAD) shouldInitiateKeyUpdate() bool { + if !a.updateAllowed() { + return false + } + if a.numRcvdWithCurrentKey >= a.keyUpdateInterval { + a.logger.Debugf("Received %d packets with current key phase. Initiating key update to the next key phase: %s", a.numRcvdWithCurrentKey, a.keyPhase.Next()) + return true + } + if a.numSentWithCurrentKey >= a.keyUpdateInterval { + a.logger.Debugf("Sent %d packets with current key phase. Initiating key update to the next key phase: %s", a.numSentWithCurrentKey, a.keyPhase.Next()) + return true + } + return false +} + func (a *updatableAEAD) KeyPhase() protocol.KeyPhase { + if a.shouldInitiateKeyUpdate() { + a.rollKeys() + } return a.keyPhase } diff --git a/internal/handshake/updatable_aead_test.go b/internal/handshake/updatable_aead_test.go index b29b3d83..314d048d 100644 --- a/internal/handshake/updatable_aead_test.go +++ b/internal/handshake/updatable_aead_test.go @@ -5,6 +5,7 @@ import ( "crypto/aes" "crypto/cipher" "crypto/rand" + "os" "github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/utils" @@ -95,79 +96,140 @@ var _ = Describe("Updatable AEAD", func() { }) Context("key updates", func() { - It("updates keys", func() { - Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseZero)) - encrypted0 := server.Seal(nil, msg, 0x1337, ad) - server.rollKeys() - Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseOne)) - encrypted1 := server.Seal(nil, msg, 0x1337, ad) - Expect(encrypted0).ToNot(Equal(encrypted1)) - // expect opening to fail. The client didn't roll keys yet - _, err := client.Open(nil, encrypted1, 0x1337, protocol.KeyPhaseZero, ad) - Expect(err).To(MatchError(ErrDecryptionFailed)) - client.rollKeys() - decrypted, err := client.Open(nil, encrypted1, 0x1337, protocol.KeyPhaseOne, ad) - Expect(err).ToNot(HaveOccurred()) - Expect(decrypted).To(Equal(msg)) + Context("receiving key updates", func() { + It("updates keys", func() { + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseZero)) + encrypted0 := server.Seal(nil, msg, 0x1337, ad) + server.rollKeys() + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseOne)) + encrypted1 := server.Seal(nil, msg, 0x1337, ad) + Expect(encrypted0).ToNot(Equal(encrypted1)) + // expect opening to fail. The client didn't roll keys yet + _, err := client.Open(nil, encrypted1, 0x1337, protocol.KeyPhaseZero, ad) + Expect(err).To(MatchError(ErrDecryptionFailed)) + client.rollKeys() + decrypted, err := client.Open(nil, encrypted1, 0x1337, protocol.KeyPhaseOne, ad) + Expect(err).ToNot(HaveOccurred()) + Expect(decrypted).To(Equal(msg)) + }) + + It("updates the keys when receiving a packet with the next key phase", func() { + // receive the first packet at key phase zero + encrypted0 := client.Seal(nil, msg, 0x42, ad) + decrypted, err := server.Open(nil, encrypted0, 0x42, protocol.KeyPhaseZero, ad) + Expect(err).ToNot(HaveOccurred()) + Expect(decrypted).To(Equal(msg)) + // send one packet at key phase zero + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseZero)) + _ = server.Seal(nil, msg, 0x1, ad) + // now received a message at key phase one + client.rollKeys() + encrypted1 := client.Seal(nil, msg, 0x43, ad) + decrypted, err = server.Open(nil, encrypted1, 0x43, protocol.KeyPhaseOne, ad) + Expect(err).ToNot(HaveOccurred()) + Expect(decrypted).To(Equal(msg)) + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseOne)) + }) + + It("opens a reordered packet with the old keys after an update", func() { + encrypted01 := client.Seal(nil, msg, 0x42, ad) + encrypted02 := client.Seal(nil, msg, 0x43, ad) + // receive the first packet with key phase 0 + _, err := server.Open(nil, encrypted01, 0x42, protocol.KeyPhaseZero, ad) + Expect(err).ToNot(HaveOccurred()) + // send one packet at key phase zero + _ = server.Seal(nil, msg, 0x1, ad) + // now receive a packet with key phase 1 + client.rollKeys() + encrypted1 := client.Seal(nil, msg, 0x44, ad) + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseZero)) + _, err = server.Open(nil, encrypted1, 0x44, protocol.KeyPhaseOne, ad) + Expect(err).ToNot(HaveOccurred()) + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseOne)) + // now receive a reordered packet with key phase 0 + decrypted, err := server.Open(nil, encrypted02, 0x43, protocol.KeyPhaseZero, ad) + Expect(err).ToNot(HaveOccurred()) + Expect(decrypted).To(Equal(msg)) + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseOne)) + }) + + It("errors when the peer starts with key phase 1", func() { + client.rollKeys() + encrypted := client.Seal(nil, msg, 0x1337, ad) + _, err := server.Open(nil, encrypted, 0x1337, protocol.KeyPhaseOne, ad) + Expect(err).To(MatchError("PROTOCOL_VIOLATION: wrong initial keyphase")) + }) + + It("errors when the peer updates keys too frequently", func() { + // receive the first packet at key phase zero + encrypted0 := client.Seal(nil, msg, 0x42, ad) + _, err := server.Open(nil, encrypted0, 0x42, protocol.KeyPhaseZero, ad) + Expect(err).ToNot(HaveOccurred()) + // now receive a packet at key phase one, before having sent any packets + client.rollKeys() + encrypted1 := client.Seal(nil, msg, 0x42, ad) + _, err = server.Open(nil, encrypted1, 0x42, protocol.KeyPhaseOne, ad) + Expect(err).To(MatchError("PROTOCOL_VIOLATION: keys updated too quickly")) + }) }) - It("updates the keys when receiving a packet with the next key phase", func() { - // receive the first packet at key phase zero - encrypted0 := client.Seal(nil, msg, 0x42, ad) - decrypted, err := server.Open(nil, encrypted0, 0x42, protocol.KeyPhaseZero, ad) - Expect(err).ToNot(HaveOccurred()) - Expect(decrypted).To(Equal(msg)) - // send one packet at key phase zero - Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseZero)) - _ = server.Seal(nil, msg, 0x1, ad) - // now received a message at key phase one - client.rollKeys() - encrypted1 := client.Seal(nil, msg, 0x43, ad) - decrypted, err = server.Open(nil, encrypted1, 0x43, protocol.KeyPhaseOne, ad) - Expect(err).ToNot(HaveOccurred()) - Expect(decrypted).To(Equal(msg)) - Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseOne)) + Context("initiating key updates", func() { + const keyUpdateInterval = 20 + + BeforeEach(func() { + Expect(server.keyUpdateInterval).To(BeEquivalentTo(protocol.KeyUpdateInterval)) + server.keyUpdateInterval = keyUpdateInterval + }) + + It("initiates a key update after sealing the maximum number of packets", func() { + for i := 0; i < keyUpdateInterval; i++ { + pn := protocol.PacketNumber(i) + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseZero)) + server.Seal(nil, msg, pn, ad) + } + // no update allowed before receiving an acknowledgement for the current key phase + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseZero)) + server.SetLargestAcked(0) + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseOne)) + }) + + It("initiates a key update after opening the maximum number of packets", func() { + for i := 0; i < keyUpdateInterval; i++ { + pn := protocol.PacketNumber(i) + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseZero)) + encrypted := client.Seal(nil, msg, pn, ad) + _, err := server.Open(nil, encrypted, pn, protocol.KeyPhaseZero, ad) + Expect(err).ToNot(HaveOccurred()) + } + // no update allowed before receiving an acknowledgement for the current key phase + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseZero)) + server.Seal(nil, msg, 1, ad) + server.SetLargestAcked(1) + Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseOne)) + }) }) - It("opens a reordered packet with the old keys after an update", func() { - encrypted01 := client.Seal(nil, msg, 0x42, ad) - encrypted02 := client.Seal(nil, msg, 0x43, ad) - // receive the first packet with key phase 0 - _, err := server.Open(nil, encrypted01, 0x42, protocol.KeyPhaseZero, ad) - Expect(err).ToNot(HaveOccurred()) - // send one packet at key phase zero - _ = server.Seal(nil, msg, 0x1, ad) - // now receive a packet with key phase 1 - client.rollKeys() - encrypted1 := client.Seal(nil, msg, 0x44, ad) - Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseZero)) - _, err = server.Open(nil, encrypted1, 0x44, protocol.KeyPhaseOne, ad) - Expect(err).ToNot(HaveOccurred()) - Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseOne)) - // now receive a reordered packet with key phase 0 - decrypted, err := server.Open(nil, encrypted02, 0x43, protocol.KeyPhaseZero, ad) - Expect(err).ToNot(HaveOccurred()) - Expect(decrypted).To(Equal(msg)) - Expect(server.KeyPhase()).To(Equal(protocol.KeyPhaseOne)) - }) + Context("reading the key update env", func() { + AfterEach(func() { + os.Setenv(keyUpdateEnv, "") + setKeyUpdateInterval() + }) - It("errors when the peer starts with key phase 1", func() { - client.rollKeys() - encrypted := client.Seal(nil, msg, 0x1337, ad) - _, err := server.Open(nil, encrypted, 0x1337, protocol.KeyPhaseOne, ad) - Expect(err).To(MatchError("PROTOCOL_VIOLATION: wrong initial keyphase")) - }) + It("uses the default value if the env is not set", func() { + setKeyUpdateInterval() + Expect(keyUpdateInterval).To(BeEquivalentTo(protocol.KeyUpdateInterval)) + }) - It("errors when the peer updates keys too frequently", func() { - // receive the first packet at key phase zero - encrypted0 := client.Seal(nil, msg, 0x42, ad) - _, err := server.Open(nil, encrypted0, 0x42, protocol.KeyPhaseZero, ad) - Expect(err).ToNot(HaveOccurred()) - // now receive a packet at key phase one, before having sent any packets - client.rollKeys() - encrypted1 := client.Seal(nil, msg, 0x42, ad) - _, err = server.Open(nil, encrypted1, 0x42, protocol.KeyPhaseOne, ad) - Expect(err).To(MatchError("PROTOCOL_VIOLATION: keys updated too quickly")) + It("uses the env", func() { + os.Setenv(keyUpdateEnv, "1337") + setKeyUpdateInterval() + Expect(keyUpdateInterval).To(BeEquivalentTo(1337)) + }) + + It("panics when it can't parse the env", func() { + os.Setenv(keyUpdateEnv, "foobar") + Expect(setKeyUpdateInterval).To(Panic()) + }) }) }) }) diff --git a/internal/mocks/crypto_setup.go b/internal/mocks/crypto_setup.go index 77ed0bed..38449457 100644 --- a/internal/mocks/crypto_setup.go +++ b/internal/mocks/crypto_setup.go @@ -182,18 +182,6 @@ func (mr *MockCryptoSetupMockRecorder) HandleMessage(arg0, arg1 interface{}) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleMessage", reflect.TypeOf((*MockCryptoSetup)(nil).HandleMessage), arg0, arg1) } -// Received1RTTAck mocks base method -func (m *MockCryptoSetup) Received1RTTAck() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Received1RTTAck") -} - -// Received1RTTAck indicates an expected call of Received1RTTAck -func (mr *MockCryptoSetupMockRecorder) Received1RTTAck() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Received1RTTAck", reflect.TypeOf((*MockCryptoSetup)(nil).Received1RTTAck)) -} - // RunHandshake mocks base method func (m *MockCryptoSetup) RunHandshake() { m.ctrl.T.Helper() @@ -205,3 +193,15 @@ func (mr *MockCryptoSetupMockRecorder) RunHandshake() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunHandshake", reflect.TypeOf((*MockCryptoSetup)(nil).RunHandshake)) } + +// SetLargest1RTTAcked mocks base method +func (m *MockCryptoSetup) SetLargest1RTTAcked(arg0 protocol.PacketNumber) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetLargest1RTTAcked", arg0) +} + +// SetLargest1RTTAcked indicates an expected call of SetLargest1RTTAcked +func (mr *MockCryptoSetupMockRecorder) SetLargest1RTTAcked(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLargest1RTTAcked", reflect.TypeOf((*MockCryptoSetup)(nil).SetLargest1RTTAcked), arg0) +} diff --git a/internal/protocol/params.go b/internal/protocol/params.go index 73c13d07..8a6d3444 100644 --- a/internal/protocol/params.go +++ b/internal/protocol/params.go @@ -139,3 +139,6 @@ const MaxAckDelay = 25 * time.Millisecond // MaxAckDelayInclGranularity is the max_ack_delay including the timer granularity. // This is the value that should be advertised to the peer. const MaxAckDelayInclGranularity = MaxAckDelay + TimerGranularity + +// KeyUpdateInterval is the maximum number of packets we send or receive before initiating a key udpate. +const KeyUpdateInterval = 100 * 1000 diff --git a/session.go b/session.go index d92f70c5..8b8939a2 100644 --- a/session.go +++ b/session.go @@ -50,7 +50,7 @@ type streamManager interface { type cryptoStreamHandler interface { RunHandshake() ChangeConnectionID(protocol.ConnectionID) error - Received1RTTAck() + SetLargest1RTTAcked(protocol.PacketNumber) io.Closer ConnectionState() tls.ConnectionState } @@ -890,7 +890,7 @@ func (s *session) handleAckFrame(frame *wire.AckFrame, pn protocol.PacketNumber, } if encLevel == protocol.Encryption1RTT { s.receivedPacketHandler.IgnoreBelow(s.sentPacketHandler.GetLowestPacketNotConfirmedAcked()) - s.cryptoStreamHandler.Received1RTTAck() + s.cryptoStreamHandler.SetLargest1RTTAcked(frame.LargestAcked()) } return nil } diff --git a/session_test.go b/session_test.go index 5399f938..03f2ebdf 100644 --- a/session_test.go +++ b/session_test.go @@ -163,7 +163,7 @@ var _ = Describe("Session", func() { }) It("tells the ReceivedPacketHandler to ignore low ranges", func() { - cryptoSetup.EXPECT().Received1RTTAck() + cryptoSetup.EXPECT().SetLargest1RTTAcked(protocol.PacketNumber(3)) ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 3}}} sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) sph.EXPECT().ReceivedAck(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any())