github.com/ooni/psiphon/tunnel-core@v0.0.0-20230105123940-fe12a24c96ee/oovendor/quic-go/crypto_stream.go (about)

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