1package quic 2 3import ( 4 "crypto/rand" 5 "fmt" 6 7 "github.com/lucas-clemente/quic-go/internal/protocol" 8 "github.com/lucas-clemente/quic-go/internal/qerr" 9 "github.com/lucas-clemente/quic-go/internal/wire" 10 11 . "github.com/onsi/ginkgo" 12 . "github.com/onsi/gomega" 13) 14 15func createHandshakeMessage(len int) []byte { 16 msg := make([]byte, 4+len) 17 rand.Read(msg[:1]) // random message type 18 msg[1] = uint8(len >> 16) 19 msg[2] = uint8(len >> 8) 20 msg[3] = uint8(len) 21 rand.Read(msg[4:]) 22 return msg 23} 24 25var _ = Describe("Crypto Stream", func() { 26 var str cryptoStream 27 28 BeforeEach(func() { 29 str = newCryptoStream() 30 }) 31 32 Context("handling incoming data", func() { 33 It("handles in-order CRYPTO frames", func() { 34 msg := createHandshakeMessage(6) 35 err := str.HandleCryptoFrame(&wire.CryptoFrame{Data: msg}) 36 Expect(err).ToNot(HaveOccurred()) 37 Expect(str.GetCryptoData()).To(Equal(msg)) 38 Expect(str.GetCryptoData()).To(BeNil()) 39 }) 40 41 It("handles multiple messages in one CRYPTO frame", func() { 42 msg1 := createHandshakeMessage(6) 43 msg2 := createHandshakeMessage(10) 44 msg := append(append([]byte{}, msg1...), msg2...) 45 err := str.HandleCryptoFrame(&wire.CryptoFrame{Data: msg}) 46 Expect(err).ToNot(HaveOccurred()) 47 Expect(str.GetCryptoData()).To(Equal(msg1)) 48 Expect(str.GetCryptoData()).To(Equal(msg2)) 49 Expect(str.GetCryptoData()).To(BeNil()) 50 }) 51 52 It("errors if the frame exceeds the maximum offset", func() { 53 Expect(str.HandleCryptoFrame(&wire.CryptoFrame{ 54 Offset: protocol.MaxCryptoStreamOffset - 5, 55 Data: []byte("foobar"), 56 })).To(MatchError(&qerr.TransportError{ 57 ErrorCode: qerr.CryptoBufferExceeded, 58 ErrorMessage: fmt.Sprintf("received invalid offset %d on crypto stream, maximum allowed %d", protocol.MaxCryptoStreamOffset+1, protocol.MaxCryptoStreamOffset), 59 })) 60 }) 61 62 It("handles messages split over multiple CRYPTO frames", func() { 63 msg := createHandshakeMessage(6) 64 err := str.HandleCryptoFrame(&wire.CryptoFrame{ 65 Data: msg[:4], 66 }) 67 Expect(err).ToNot(HaveOccurred()) 68 Expect(str.GetCryptoData()).To(BeNil()) 69 err = str.HandleCryptoFrame(&wire.CryptoFrame{ 70 Offset: 4, 71 Data: msg[4:], 72 }) 73 Expect(err).ToNot(HaveOccurred()) 74 Expect(str.GetCryptoData()).To(Equal(msg)) 75 Expect(str.GetCryptoData()).To(BeNil()) 76 }) 77 78 It("handles out-of-order CRYPTO frames", func() { 79 msg := createHandshakeMessage(6) 80 err := str.HandleCryptoFrame(&wire.CryptoFrame{ 81 Offset: 4, 82 Data: msg[4:], 83 }) 84 Expect(err).ToNot(HaveOccurred()) 85 Expect(str.GetCryptoData()).To(BeNil()) 86 err = str.HandleCryptoFrame(&wire.CryptoFrame{ 87 Data: msg[:4], 88 }) 89 Expect(err).ToNot(HaveOccurred()) 90 Expect(str.GetCryptoData()).To(Equal(msg)) 91 Expect(str.GetCryptoData()).To(BeNil()) 92 }) 93 94 Context("finishing", func() { 95 It("errors if there's still data to read after finishing", func() { 96 Expect(str.HandleCryptoFrame(&wire.CryptoFrame{ 97 Data: createHandshakeMessage(5), 98 Offset: 10, 99 })).To(Succeed()) 100 Expect(str.Finish()).To(MatchError(&qerr.TransportError{ 101 ErrorCode: qerr.ProtocolViolation, 102 ErrorMessage: "encryption level changed, but crypto stream has more data to read", 103 })) 104 }) 105 106 It("works with reordered data", func() { 107 f1 := &wire.CryptoFrame{ 108 Data: []byte("foo"), 109 } 110 f2 := &wire.CryptoFrame{ 111 Offset: 3, 112 Data: []byte("bar"), 113 } 114 Expect(str.HandleCryptoFrame(f2)).To(Succeed()) 115 Expect(str.HandleCryptoFrame(f1)).To(Succeed()) 116 Expect(str.Finish()).To(Succeed()) 117 Expect(str.HandleCryptoFrame(f2)).To(Succeed()) 118 }) 119 120 It("rejects new crypto data after finishing", func() { 121 Expect(str.Finish()).To(Succeed()) 122 Expect(str.HandleCryptoFrame(&wire.CryptoFrame{ 123 Data: createHandshakeMessage(5), 124 })).To(MatchError(&qerr.TransportError{ 125 ErrorCode: qerr.ProtocolViolation, 126 ErrorMessage: "received crypto data after change of encryption level", 127 })) 128 }) 129 130 It("ignores crypto data below the maximum offset received before finishing", func() { 131 msg := createHandshakeMessage(15) 132 Expect(str.HandleCryptoFrame(&wire.CryptoFrame{ 133 Data: msg, 134 })).To(Succeed()) 135 Expect(str.GetCryptoData()).To(Equal(msg)) 136 Expect(str.Finish()).To(Succeed()) 137 Expect(str.HandleCryptoFrame(&wire.CryptoFrame{ 138 Offset: protocol.ByteCount(len(msg) - 6), 139 Data: []byte("foobar"), 140 })).To(Succeed()) 141 }) 142 }) 143 }) 144 145 Context("writing data", func() { 146 It("says if it has data", func() { 147 Expect(str.HasData()).To(BeFalse()) 148 _, err := str.Write([]byte("foobar")) 149 Expect(err).ToNot(HaveOccurred()) 150 Expect(str.HasData()).To(BeTrue()) 151 }) 152 153 It("pops crypto frames", func() { 154 _, err := str.Write([]byte("foobar")) 155 Expect(err).ToNot(HaveOccurred()) 156 f := str.PopCryptoFrame(1000) 157 Expect(f).ToNot(BeNil()) 158 Expect(f.Offset).To(BeZero()) 159 Expect(f.Data).To(Equal([]byte("foobar"))) 160 }) 161 162 It("coalesces multiple writes", func() { 163 _, err := str.Write([]byte("foo")) 164 Expect(err).ToNot(HaveOccurred()) 165 _, err = str.Write([]byte("bar")) 166 Expect(err).ToNot(HaveOccurred()) 167 f := str.PopCryptoFrame(1000) 168 Expect(f).ToNot(BeNil()) 169 Expect(f.Offset).To(BeZero()) 170 Expect(f.Data).To(Equal([]byte("foobar"))) 171 }) 172 173 It("respects the maximum size", func() { 174 frameHeaderLen := (&wire.CryptoFrame{}).Length(protocol.VersionWhatever) 175 _, err := str.Write([]byte("foobar")) 176 Expect(err).ToNot(HaveOccurred()) 177 f := str.PopCryptoFrame(frameHeaderLen + 3) 178 Expect(f).ToNot(BeNil()) 179 Expect(f.Offset).To(BeZero()) 180 Expect(f.Data).To(Equal([]byte("foo"))) 181 f = str.PopCryptoFrame(frameHeaderLen + 3) 182 Expect(f).ToNot(BeNil()) 183 Expect(f.Offset).To(Equal(protocol.ByteCount(3))) 184 Expect(f.Data).To(Equal([]byte("bar"))) 185 }) 186 }) 187}) 188