1package quic 2 3import ( 4 "bytes" 5 "errors" 6 "time" 7 8 "github.com/lucas-clemente/quic-go/internal/handshake" 9 "github.com/lucas-clemente/quic-go/internal/mocks" 10 "github.com/lucas-clemente/quic-go/internal/protocol" 11 "github.com/lucas-clemente/quic-go/internal/qerr" 12 "github.com/lucas-clemente/quic-go/internal/wire" 13 14 "github.com/golang/mock/gomock" 15 16 . "github.com/onsi/ginkgo" 17 . "github.com/onsi/gomega" 18) 19 20var _ = Describe("Packet Unpacker", func() { 21 const version = protocol.VersionTLS 22 23 var ( 24 unpacker *packetUnpacker 25 cs *mocks.MockCryptoSetup 26 connID = protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef} 27 payload = []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") 28 ) 29 30 getHeader := func(extHdr *wire.ExtendedHeader) (*wire.Header, []byte) { 31 buf := &bytes.Buffer{} 32 ExpectWithOffset(1, extHdr.Write(buf, version)).To(Succeed()) 33 hdrLen := buf.Len() 34 if extHdr.Length > protocol.ByteCount(extHdr.PacketNumberLen) { 35 buf.Write(make([]byte, int(extHdr.Length)-int(extHdr.PacketNumberLen))) 36 } 37 hdr, _, _, err := wire.ParsePacket(buf.Bytes(), connID.Len()) 38 ExpectWithOffset(1, err).ToNot(HaveOccurred()) 39 return hdr, buf.Bytes()[:hdrLen] 40 } 41 42 BeforeEach(func() { 43 cs = mocks.NewMockCryptoSetup(mockCtrl) 44 unpacker = newPacketUnpacker(cs, version).(*packetUnpacker) 45 }) 46 47 It("errors when the packet is too small to obtain the header decryption sample, for long headers", func() { 48 extHdr := &wire.ExtendedHeader{ 49 Header: wire.Header{ 50 IsLongHeader: true, 51 Type: protocol.PacketTypeHandshake, 52 DestConnectionID: connID, 53 Version: version, 54 }, 55 PacketNumber: 1337, 56 PacketNumberLen: protocol.PacketNumberLen2, 57 } 58 hdr, hdrRaw := getHeader(extHdr) 59 data := append(hdrRaw, make([]byte, 2 /* fill up packet number */ +15 /* need 16 bytes */)...) 60 opener := mocks.NewMockLongHeaderOpener(mockCtrl) 61 cs.EXPECT().GetHandshakeOpener().Return(opener, nil) 62 _, err := unpacker.Unpack(hdr, time.Now(), data) 63 Expect(errors.Is(err, &headerParseError{})).To(BeTrue()) 64 var headerErr *headerParseError 65 Expect(errors.As(err, &headerErr)).To(BeTrue()) 66 Expect(err).To(MatchError("Packet too small. Expected at least 20 bytes after the header, got 19")) 67 }) 68 69 It("errors when the packet is too small to obtain the header decryption sample, for short headers", func() { 70 extHdr := &wire.ExtendedHeader{ 71 Header: wire.Header{DestConnectionID: connID}, 72 PacketNumber: 1337, 73 PacketNumberLen: protocol.PacketNumberLen2, 74 } 75 hdr, hdrRaw := getHeader(extHdr) 76 data := append(hdrRaw, make([]byte, 2 /* fill up packet number */ +15 /* need 16 bytes */)...) 77 opener := mocks.NewMockShortHeaderOpener(mockCtrl) 78 cs.EXPECT().Get1RTTOpener().Return(opener, nil) 79 _, err := unpacker.Unpack(hdr, time.Now(), data) 80 Expect(errors.Is(err, &headerParseError{})).To(BeTrue()) 81 var headerErr *headerParseError 82 Expect(errors.As(err, &headerErr)).To(BeTrue()) 83 Expect(err).To(MatchError("Packet too small. Expected at least 20 bytes after the header, got 19")) 84 }) 85 86 It("opens Initial packets", func() { 87 extHdr := &wire.ExtendedHeader{ 88 Header: wire.Header{ 89 IsLongHeader: true, 90 Type: protocol.PacketTypeInitial, 91 Length: 3 + 6, // packet number len + payload 92 DestConnectionID: connID, 93 Version: version, 94 }, 95 PacketNumber: 2, 96 PacketNumberLen: 3, 97 } 98 hdr, hdrRaw := getHeader(extHdr) 99 opener := mocks.NewMockLongHeaderOpener(mockCtrl) 100 gomock.InOrder( 101 cs.EXPECT().GetInitialOpener().Return(opener, nil), 102 opener.EXPECT().DecryptHeader(gomock.Any(), gomock.Any(), gomock.Any()), 103 opener.EXPECT().DecodePacketNumber(protocol.PacketNumber(2), protocol.PacketNumberLen3).Return(protocol.PacketNumber(1234)), 104 opener.EXPECT().Open(gomock.Any(), payload, protocol.PacketNumber(1234), hdrRaw).Return([]byte("decrypted"), nil), 105 ) 106 packet, err := unpacker.Unpack(hdr, time.Now(), append(hdrRaw, payload...)) 107 Expect(err).ToNot(HaveOccurred()) 108 Expect(packet.encryptionLevel).To(Equal(protocol.EncryptionInitial)) 109 Expect(packet.data).To(Equal([]byte("decrypted"))) 110 }) 111 112 It("opens 0-RTT packets", func() { 113 extHdr := &wire.ExtendedHeader{ 114 Header: wire.Header{ 115 IsLongHeader: true, 116 Type: protocol.PacketType0RTT, 117 Length: 3 + 6, // packet number len + payload 118 DestConnectionID: connID, 119 Version: version, 120 }, 121 PacketNumber: 20, 122 PacketNumberLen: 2, 123 } 124 hdr, hdrRaw := getHeader(extHdr) 125 opener := mocks.NewMockLongHeaderOpener(mockCtrl) 126 gomock.InOrder( 127 cs.EXPECT().Get0RTTOpener().Return(opener, nil), 128 opener.EXPECT().DecryptHeader(gomock.Any(), gomock.Any(), gomock.Any()), 129 opener.EXPECT().DecodePacketNumber(protocol.PacketNumber(20), protocol.PacketNumberLen2).Return(protocol.PacketNumber(321)), 130 opener.EXPECT().Open(gomock.Any(), payload, protocol.PacketNumber(321), hdrRaw).Return([]byte("decrypted"), nil), 131 ) 132 packet, err := unpacker.Unpack(hdr, time.Now(), append(hdrRaw, payload...)) 133 Expect(err).ToNot(HaveOccurred()) 134 Expect(packet.encryptionLevel).To(Equal(protocol.Encryption0RTT)) 135 Expect(packet.data).To(Equal([]byte("decrypted"))) 136 }) 137 138 It("opens short header packets", func() { 139 extHdr := &wire.ExtendedHeader{ 140 Header: wire.Header{DestConnectionID: connID}, 141 KeyPhase: protocol.KeyPhaseOne, 142 PacketNumber: 99, 143 PacketNumberLen: protocol.PacketNumberLen4, 144 } 145 hdr, hdrRaw := getHeader(extHdr) 146 opener := mocks.NewMockShortHeaderOpener(mockCtrl) 147 now := time.Now() 148 gomock.InOrder( 149 cs.EXPECT().Get1RTTOpener().Return(opener, nil), 150 opener.EXPECT().DecryptHeader(gomock.Any(), gomock.Any(), gomock.Any()), 151 opener.EXPECT().DecodePacketNumber(protocol.PacketNumber(99), protocol.PacketNumberLen4).Return(protocol.PacketNumber(321)), 152 opener.EXPECT().Open(gomock.Any(), payload, now, protocol.PacketNumber(321), protocol.KeyPhaseOne, hdrRaw).Return([]byte("decrypted"), nil), 153 ) 154 packet, err := unpacker.Unpack(hdr, now, append(hdrRaw, payload...)) 155 Expect(err).ToNot(HaveOccurred()) 156 Expect(packet.encryptionLevel).To(Equal(protocol.Encryption1RTT)) 157 Expect(packet.data).To(Equal([]byte("decrypted"))) 158 }) 159 160 It("returns the error when getting the sealer fails", func() { 161 extHdr := &wire.ExtendedHeader{ 162 Header: wire.Header{DestConnectionID: connID}, 163 PacketNumber: 0x1337, 164 PacketNumberLen: 2, 165 } 166 hdr, hdrRaw := getHeader(extHdr) 167 cs.EXPECT().Get1RTTOpener().Return(nil, handshake.ErrKeysNotYetAvailable) 168 _, err := unpacker.Unpack(hdr, time.Now(), append(hdrRaw, payload...)) 169 Expect(err).To(MatchError(handshake.ErrKeysNotYetAvailable)) 170 }) 171 172 It("returns the error when unpacking fails", func() { 173 extHdr := &wire.ExtendedHeader{ 174 Header: wire.Header{ 175 IsLongHeader: true, 176 Type: protocol.PacketTypeHandshake, 177 Length: 3, // packet number len 178 DestConnectionID: connID, 179 Version: version, 180 }, 181 PacketNumber: 2, 182 PacketNumberLen: 3, 183 } 184 hdr, hdrRaw := getHeader(extHdr) 185 opener := mocks.NewMockLongHeaderOpener(mockCtrl) 186 cs.EXPECT().GetHandshakeOpener().Return(opener, nil) 187 opener.EXPECT().DecryptHeader(gomock.Any(), gomock.Any(), gomock.Any()) 188 opener.EXPECT().DecodePacketNumber(gomock.Any(), gomock.Any()) 189 opener.EXPECT().Open(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, qerr.CryptoBufferExceeded) 190 _, err := unpacker.Unpack(hdr, time.Now(), append(hdrRaw, payload...)) 191 Expect(err).To(MatchError(qerr.CryptoBufferExceeded)) 192 }) 193 194 It("defends against the timing side-channel when the reserved bits are wrong, for long header packets", func() { 195 extHdr := &wire.ExtendedHeader{ 196 Header: wire.Header{ 197 IsLongHeader: true, 198 Type: protocol.PacketTypeHandshake, 199 DestConnectionID: connID, 200 Version: version, 201 }, 202 PacketNumber: 0x1337, 203 PacketNumberLen: 2, 204 } 205 hdr, hdrRaw := getHeader(extHdr) 206 hdrRaw[0] |= 0xc 207 opener := mocks.NewMockLongHeaderOpener(mockCtrl) 208 opener.EXPECT().DecryptHeader(gomock.Any(), gomock.Any(), gomock.Any()) 209 cs.EXPECT().GetHandshakeOpener().Return(opener, nil) 210 opener.EXPECT().DecodePacketNumber(gomock.Any(), gomock.Any()) 211 opener.EXPECT().Open(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte("payload"), nil) 212 _, err := unpacker.Unpack(hdr, time.Now(), append(hdrRaw, payload...)) 213 Expect(err).To(MatchError(wire.ErrInvalidReservedBits)) 214 }) 215 216 It("defends against the timing side-channel when the reserved bits are wrong, for short header packets", func() { 217 extHdr := &wire.ExtendedHeader{ 218 Header: wire.Header{DestConnectionID: connID}, 219 PacketNumber: 0x1337, 220 PacketNumberLen: 2, 221 } 222 hdr, hdrRaw := getHeader(extHdr) 223 hdrRaw[0] |= 0x18 224 opener := mocks.NewMockShortHeaderOpener(mockCtrl) 225 opener.EXPECT().DecryptHeader(gomock.Any(), gomock.Any(), gomock.Any()) 226 cs.EXPECT().Get1RTTOpener().Return(opener, nil) 227 opener.EXPECT().DecodePacketNumber(gomock.Any(), gomock.Any()) 228 opener.EXPECT().Open(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte("payload"), nil) 229 _, err := unpacker.Unpack(hdr, time.Now(), append(hdrRaw, payload...)) 230 Expect(err).To(MatchError(wire.ErrInvalidReservedBits)) 231 }) 232 233 It("returns the decryption error, when unpacking a packet with wrong reserved bits fails", func() { 234 extHdr := &wire.ExtendedHeader{ 235 Header: wire.Header{DestConnectionID: connID}, 236 PacketNumber: 0x1337, 237 PacketNumberLen: 2, 238 } 239 hdr, hdrRaw := getHeader(extHdr) 240 hdrRaw[0] |= 0x18 241 opener := mocks.NewMockShortHeaderOpener(mockCtrl) 242 opener.EXPECT().DecryptHeader(gomock.Any(), gomock.Any(), gomock.Any()) 243 cs.EXPECT().Get1RTTOpener().Return(opener, nil) 244 opener.EXPECT().DecodePacketNumber(gomock.Any(), gomock.Any()) 245 opener.EXPECT().Open(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, handshake.ErrDecryptionFailed) 246 _, err := unpacker.Unpack(hdr, time.Now(), append(hdrRaw, payload...)) 247 Expect(err).To(MatchError(handshake.ErrDecryptionFailed)) 248 }) 249 250 It("decrypts the header", func() { 251 extHdr := &wire.ExtendedHeader{ 252 Header: wire.Header{ 253 IsLongHeader: true, 254 Type: protocol.PacketTypeHandshake, 255 Length: 3, // packet number len 256 DestConnectionID: connID, 257 Version: version, 258 }, 259 PacketNumber: 0x1337, 260 PacketNumberLen: 2, 261 } 262 hdr, hdrRaw := getHeader(extHdr) 263 origHdrRaw := append([]byte{}, hdrRaw...) // save a copy of the header 264 firstHdrByte := hdrRaw[0] 265 hdrRaw[0] ^= 0xff // invert the first byte 266 hdrRaw[len(hdrRaw)-2] ^= 0xff // invert the packet number 267 hdrRaw[len(hdrRaw)-1] ^= 0xff // invert the packet number 268 Expect(hdrRaw[0]).ToNot(Equal(firstHdrByte)) 269 opener := mocks.NewMockLongHeaderOpener(mockCtrl) 270 cs.EXPECT().GetHandshakeOpener().Return(opener, nil) 271 gomock.InOrder( 272 // we're using a 2 byte packet number, so the sample starts at the 3rd payload byte 273 opener.EXPECT().DecryptHeader( 274 []byte{3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}, 275 &hdrRaw[0], 276 append(hdrRaw[len(hdrRaw)-2:], []byte{1, 2}...)).Do(func(_ []byte, firstByte *byte, pnBytes []byte) { 277 *firstByte ^= 0xff // invert the first byte back 278 for i := range pnBytes { 279 pnBytes[i] ^= 0xff // invert the packet number bytes 280 } 281 }), 282 opener.EXPECT().DecodePacketNumber(protocol.PacketNumber(0x1337), protocol.PacketNumberLen2).Return(protocol.PacketNumber(0x7331)), 283 opener.EXPECT().Open(gomock.Any(), gomock.Any(), protocol.PacketNumber(0x7331), origHdrRaw).Return([]byte{0}, nil), 284 ) 285 data := hdrRaw 286 for i := 1; i <= 100; i++ { 287 data = append(data, uint8(i)) 288 } 289 packet, err := unpacker.Unpack(hdr, time.Now(), data) 290 Expect(err).ToNot(HaveOccurred()) 291 Expect(packet.packetNumber).To(Equal(protocol.PacketNumber(0x7331))) 292 }) 293}) 294