crypto_stream.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package quic
  2. import (
  3. "errors"
  4. "fmt"
  5. "io"
  6. "github.com/Psiphon-Labs/quic-go/internal/protocol"
  7. "github.com/Psiphon-Labs/quic-go/internal/qerr"
  8. "github.com/Psiphon-Labs/quic-go/internal/utils"
  9. "github.com/Psiphon-Labs/quic-go/internal/wire"
  10. )
  11. type cryptoStream interface {
  12. // for receiving data
  13. HandleCryptoFrame(*wire.CryptoFrame) error
  14. GetCryptoData() []byte
  15. Finish() error
  16. // for sending data
  17. io.Writer
  18. HasData() bool
  19. PopCryptoFrame(protocol.ByteCount) *wire.CryptoFrame
  20. }
  21. type postHandshakeCryptoStream struct {
  22. cryptoStream
  23. framer framer
  24. }
  25. func newPostHandshakeCryptoStream(framer framer) cryptoStream {
  26. return &postHandshakeCryptoStream{
  27. cryptoStream: newCryptoStream(),
  28. framer: framer,
  29. }
  30. }
  31. // Write writes post-handshake messages.
  32. // For simplicity, post-handshake crypto messages are treated as control frames.
  33. // The framer functions as a stack (LIFO), so if there are multiple writes,
  34. // they will be returned in the opposite order.
  35. // This is acceptable, since post-handshake crypto messages are very rare.
  36. func (s *postHandshakeCryptoStream) Write(p []byte) (int, error) {
  37. n, err := s.cryptoStream.Write(p)
  38. if err != nil {
  39. return n, err
  40. }
  41. for s.cryptoStream.HasData() {
  42. s.framer.QueueControlFrame(s.PopCryptoFrame(protocol.MaxPostHandshakeCryptoFrameSize))
  43. }
  44. return n, nil
  45. }
  46. type cryptoStreamImpl struct {
  47. queue *frameSorter
  48. msgBuf []byte
  49. highestOffset protocol.ByteCount
  50. finished bool
  51. writeOffset protocol.ByteCount
  52. writeBuf []byte
  53. }
  54. func newCryptoStream() cryptoStream {
  55. return &cryptoStreamImpl{queue: newFrameSorter()}
  56. }
  57. func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error {
  58. highestOffset := f.Offset + protocol.ByteCount(len(f.Data))
  59. if maxOffset := highestOffset; maxOffset > protocol.MaxCryptoStreamOffset {
  60. return qerr.Error(qerr.CryptoBufferExceeded, fmt.Sprintf("received invalid offset %d on crypto stream, maximum allowed %d", maxOffset, protocol.MaxCryptoStreamOffset))
  61. }
  62. if s.finished {
  63. if highestOffset > s.highestOffset {
  64. // reject crypto data received after this stream was already finished
  65. return qerr.Error(qerr.ProtocolViolation, "received crypto data after change of encryption level")
  66. }
  67. // ignore data with a smaller offset than the highest received
  68. // could e.g. be a retransmission
  69. return nil
  70. }
  71. s.highestOffset = utils.MaxByteCount(s.highestOffset, highestOffset)
  72. if err := s.queue.Push(f.Data, f.Offset, nil); err != nil {
  73. return err
  74. }
  75. for {
  76. _, data, _ := s.queue.Pop()
  77. if data == nil {
  78. return nil
  79. }
  80. s.msgBuf = append(s.msgBuf, data...)
  81. }
  82. }
  83. // GetCryptoData retrieves data that was received in CRYPTO frames
  84. func (s *cryptoStreamImpl) GetCryptoData() []byte {
  85. if len(s.msgBuf) < 4 {
  86. return nil
  87. }
  88. msgLen := 4 + int(s.msgBuf[1])<<16 + int(s.msgBuf[2])<<8 + int(s.msgBuf[3])
  89. if len(s.msgBuf) < msgLen {
  90. return nil
  91. }
  92. msg := make([]byte, msgLen)
  93. copy(msg, s.msgBuf[:msgLen])
  94. s.msgBuf = s.msgBuf[msgLen:]
  95. return msg
  96. }
  97. func (s *cryptoStreamImpl) Finish() error {
  98. if s.queue.HasMoreData() {
  99. return errors.New("encryption level changed, but crypto stream has more data to read")
  100. }
  101. s.finished = true
  102. return nil
  103. }
  104. // Writes writes data that should be sent out in CRYPTO frames
  105. func (s *cryptoStreamImpl) Write(p []byte) (int, error) {
  106. s.writeBuf = append(s.writeBuf, p...)
  107. return len(p), nil
  108. }
  109. func (s *cryptoStreamImpl) HasData() bool {
  110. return len(s.writeBuf) > 0
  111. }
  112. func (s *cryptoStreamImpl) PopCryptoFrame(maxLen protocol.ByteCount) *wire.CryptoFrame {
  113. f := &wire.CryptoFrame{Offset: s.writeOffset}
  114. n := utils.MinByteCount(f.MaxDataLen(maxLen), protocol.ByteCount(len(s.writeBuf)))
  115. f.Data = s.writeBuf[:n]
  116. s.writeBuf = s.writeBuf[n:]
  117. s.writeOffset += n
  118. return f
  119. }