Repository: xvzc/SpoofDPI
File: packet/https.go (Go)

Code before:
type TLSMessage struct {
	Header     TLSHeader
	Raw        []byte //Header + Payload
	RawHeader  []byte
	RawPayload []byte
}

type TLSHeader struct {
	Type         TLSMessageType
	ProtoVersion uint16 // major | minor
	PayloadLen   uint16
}

func ReadTLSMessage(r io.Reader) (*TLSMessage, error) {
	var rawHeader [TLSHeaderLen]byte
	_, err := io.ReadFull(r, rawHeader[:])
	if err != nil {
		return nil, err
	}

	header := TLSHeader{
		Type:         TLSMessageType(rawHeader[0]),
		ProtoVersion: binary.BigEndian.Uint16(rawHeader[1:3]),
		PayloadLen:   binary.BigEndian.Uint16(rawHeader[3:5]),
	}
	rawLen := header.PayloadLen + TLSHeaderLen
	if rawLen < TLSHeaderLen {
		// Corrupted header? Check integer overflow
		return nil, fmt.Errorf("invalid TLS header.Type: %x, ProtoVersion: %x, PayloadLen: %x", header.Type, header.ProtoVersion, header.PayloadLen)
	}
	raw := make([]byte, rawLen)
	copy(raw[0:TLSHeaderLen], rawHeader[:])
	_, err = io.ReadFull(r, raw[TLSHeaderLen:])
	if err != nil {
		return nil, err
	}

	hello := &TLSMessage{
		Header:     header,
		Raw:        raw,
		RawHeader:  raw[:TLSHeaderLen],
		RawPayload: raw[TLSHeaderLen:],
	}
	return hello, nil
}

func (m *TLSMessage) IsClientHello() bool {
	// According to RFC 8446 section 4.
	// first byte (Raw[5]) of handshake message should be 0x1 - means client_hello
	return len(m.Raw) > TLSHeaderLen &&
		m.Header.Type == TLSHandshake &&

Review comment (suggestion):
One question about this.
```go
	header := TLSHeader{
		Type:         TLSMessageType(rawHeader[0]),
		ProtoVersion: binary.BigEndian.Uint16(rawHeader[1:3]),
		PayloadLen:   binary.BigEndian.Uint16(rawHeader[3:5]),
	}
```

According to RFC 8446, it says
```   
      enum {
          client_hello(1),
          server_hello(2),
          new_session_ticket(4),
          end_of_early_data(5),
          encrypted_extensions(8),
          certificate(11),
          certificate_request(13),
          certificate_verify(15),
          finished(20),
          key_update(24),
          message_hash(254),
          (255)
      } HandshakeType;

      struct {
          HandshakeType msg_type;    /* handshake type */
          uint24 length;             /* remaining bytes in message */
          select (Handshake.msg_type) {
              case client_hello:          ClientHello;
              case server_hello:          ServerHello;
              case end_of_early_data:     EndOfEarlyData;
              case encrypted_extensions:  EncryptedExtensions;
              case certificate_request:   CertificateRequest;
              case certificate:           Certificate;
              case certificate_verify:    CertificateVerify;
              case finished:              Finished;
              case new_session_ticket:    NewSessionTicket;
              case key_update:            KeyUpdate;
          };
      } Handshake;
```

So the first 1 byte is the type of handshake, and the following 3 bytes should be the `remaining bytes in message`

And following is the definition of ClientHello struct
```
      uint16 ProtocolVersion;
      opaque Random[32];

      uint8 CipherSuite[2];    /* Cryptographic suite selector */

      struct {
          ProtocolVersion legacy_version = 0x0303;    /* TLS v1.2 */
          Random random;
          opaque legacy_session_id<0..32>;
          CipherSuite cipher_suites<2..2^16-2>;
          opaque legacy_compression_methods<1..2^8-1>;
          Extension extensions<8..2^16-1>;
      } ClientHello;
```

If i undertood it right, shouldn't it be the 2bytes starting from `index 4` that is indicating the ProtocolVersion part like below?

```go
	header := TLSHeader{
		Type: TLSMessageType(rawHeader[0]),
		PayloadLength: TLSMessageType(rawHeader[1:4]),
		ProtoVersion: binary.BigEndian.Uint16(rawHeader[4:5]),
	}
```

Code after:

type TLSMessage struct {
	Header     TLSHeader
	Raw        []byte //Header + Payload
	RawHeader  []byte
	RawPayload []byte
}

type TLSHeader struct {
	Type         TLSMessageType
	ProtoVersion uint16 // major | minor
	PayloadLen   uint16
}

func ReadTLSMessage(r io.Reader) (*TLSMessage, error) {
	var rawHeader [TLSHeaderLen]byte
	_, err := io.ReadFull(r, rawHeader[:])
	if err != nil {
		return nil, err
	}

	header := TLSHeader{
		Type:         TLSMessageType(rawHeader[0]),
		ProtoVersion: binary.BigEndian.Uint16(rawHeader[1:3]),
		PayloadLen:   binary.BigEndian.Uint16(rawHeader[3:5]),
	}
	if header.PayloadLen > TLSMaxPayloadLen {
		// Corrupted header? Check integer overflow
		return nil, fmt.Errorf("invalid TLS header. Type: %x, ProtoVersion: %x, PayloadLen: %x", header.Type, header.ProtoVersion, header.PayloadLen)
	}
	raw := make([]byte, header.PayloadLen+TLSHeaderLen)
	copy(raw[0:TLSHeaderLen], rawHeader[:])
	_, err = io.ReadFull(r, raw[TLSHeaderLen:])
	if err != nil {
		return nil, err
	}

	hello := &TLSMessage{
		Header:     header,
		Raw:        raw,
		RawHeader:  raw[:TLSHeaderLen],
		RawPayload: raw[TLSHeaderLen:],
	}
	return hello, nil
}

func (m *TLSMessage) IsClientHello() bool {
	// According to RFC 8446 section 4.
	// first byte (Raw[5]) of handshake message should be 0x1 - means client_hello
	return len(m.Raw) > TLSHeaderLen &&
		m.Header.Type == TLSHandshake &&