mirror of https://github.com/ginuerzh/gost
12 changed files with 6415 additions and 95 deletions
@ -0,0 +1,21 @@ |
|||
MIT License |
|||
|
|||
Copyright (c) 2017 ginuerzh |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|||
SOFTWARE. |
|||
@ -0,0 +1,2 @@ |
|||
# tls-dissector |
|||
Dissect TLS handshake messages |
|||
@ -0,0 +1,75 @@ |
|||
package dissector |
|||
|
|||
import ( |
|||
"bytes" |
|||
"encoding/binary" |
|||
"io" |
|||
) |
|||
|
|||
const ( |
|||
ExtServerName uint16 = 0x0000 |
|||
) |
|||
|
|||
type Extension interface { |
|||
Type() uint16 |
|||
Bytes() []byte |
|||
} |
|||
|
|||
func ReadExtension(r io.Reader) (ext Extension, err error) { |
|||
b := make([]byte, 4) |
|||
if _, err = io.ReadFull(r, b); err != nil { |
|||
return |
|||
} |
|||
bb := make([]byte, int(binary.BigEndian.Uint16(b[2:4]))) |
|||
if _, err = io.ReadFull(r, bb); err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
t := binary.BigEndian.Uint16(b[:2]) |
|||
switch t { |
|||
case ExtServerName: |
|||
ext = &ServerNameExtension{ |
|||
NameType: bb[2], |
|||
Name: string(bb[5:]), |
|||
} |
|||
|
|||
default: |
|||
ext = &unknownExtension{ |
|||
raw: append(b, bb...), |
|||
} |
|||
} |
|||
|
|||
return |
|||
} |
|||
|
|||
type unknownExtension struct { |
|||
raw []byte |
|||
} |
|||
|
|||
func (ext *unknownExtension) Type() uint16 { |
|||
return binary.BigEndian.Uint16(ext.raw) |
|||
} |
|||
|
|||
func (ext *unknownExtension) Bytes() []byte { |
|||
return ext.raw |
|||
} |
|||
|
|||
type ServerNameExtension struct { |
|||
NameType uint8 |
|||
Name string |
|||
} |
|||
|
|||
func (ext *ServerNameExtension) Type() uint16 { |
|||
return ExtServerName |
|||
} |
|||
|
|||
func (ext *ServerNameExtension) Bytes() []byte { |
|||
buf := &bytes.Buffer{} |
|||
binary.Write(buf, binary.BigEndian, ExtServerName) |
|||
binary.Write(buf, binary.BigEndian, uint16(2+1+2+len(ext.Name))) |
|||
binary.Write(buf, binary.BigEndian, uint16(1+2+len(ext.Name))) |
|||
buf.WriteByte(ext.NameType) |
|||
binary.Write(buf, binary.BigEndian, uint16(len(ext.Name))) |
|||
buf.WriteString(ext.Name) |
|||
return buf.Bytes() |
|||
} |
|||
@ -0,0 +1,152 @@ |
|||
package dissector |
|||
|
|||
import ( |
|||
"bytes" |
|||
"encoding/binary" |
|||
"io" |
|||
) |
|||
|
|||
const ( |
|||
handshakeHeaderLen = 4 |
|||
) |
|||
|
|||
const ( |
|||
HelloRequest = 0 |
|||
ClientHello = 1 |
|||
ServerHello = 2 |
|||
) |
|||
|
|||
type Random struct { |
|||
Time uint32 |
|||
Opaque [28]byte |
|||
} |
|||
|
|||
type CipherSuite uint16 |
|||
|
|||
type CompressionMethod uint8 |
|||
|
|||
type ClientHelloHandshake struct { |
|||
Version Version |
|||
Random Random |
|||
SessionID []byte |
|||
CipherSuites []CipherSuite |
|||
CompressionMethods []CompressionMethod |
|||
Extensions []Extension |
|||
} |
|||
|
|||
func (h *ClientHelloHandshake) Encode() (data []byte, err error) { |
|||
buf := new(bytes.Buffer) |
|||
if _, err = h.WriteTo(buf); err != nil { |
|||
return |
|||
} |
|||
data = buf.Bytes() |
|||
return |
|||
} |
|||
|
|||
func (h *ClientHelloHandshake) Decode(data []byte) (err error) { |
|||
_, err = h.ReadFrom(bytes.NewReader(data)) |
|||
return |
|||
} |
|||
|
|||
func (h *ClientHelloHandshake) ReadFrom(r io.Reader) (n int64, err error) { |
|||
b := make([]byte, handshakeHeaderLen) |
|||
nn, err := io.ReadFull(r, b) |
|||
n += int64(nn) |
|||
if err != nil { |
|||
return |
|||
} |
|||
|
|||
if b[0] != ClientHello { |
|||
err = ErrBadType |
|||
return |
|||
} |
|||
|
|||
length := int(b[1])<<16 | int(b[2])<<8 | int(b[3]) |
|||
b = make([]byte, length) |
|||
nn, err = io.ReadFull(r, b) |
|||
n += int64(nn) |
|||
if err != nil { |
|||
return |
|||
} |
|||
h.Version = Version(binary.BigEndian.Uint16(b[:2])) |
|||
|
|||
pos := 2 |
|||
h.Random.Time = binary.BigEndian.Uint32(b[pos : pos+4]) |
|||
pos += 4 |
|||
copy(h.Random.Opaque[:], b[pos:pos+28]) |
|||
pos += 28 |
|||
|
|||
sessionLen := int(b[pos]) |
|||
pos++ |
|||
h.SessionID = make([]byte, sessionLen) |
|||
copy(h.SessionID, b[pos:pos+sessionLen]) |
|||
pos += sessionLen |
|||
|
|||
cipherLen := int(binary.BigEndian.Uint16(b[pos : pos+2])) |
|||
pos += 2 |
|||
for i := 0; i < cipherLen/2; i++ { |
|||
h.CipherSuites = append(h.CipherSuites, CipherSuite(binary.BigEndian.Uint16(b[pos:pos+2]))) |
|||
pos += 2 |
|||
} |
|||
|
|||
compLen := int(b[pos]) |
|||
pos++ |
|||
for i := 0; i < compLen; i++ { |
|||
h.CompressionMethods = append(h.CompressionMethods, CompressionMethod(b[pos])) |
|||
pos++ |
|||
} |
|||
|
|||
// extLen := int(binary.BigEndian.Uint16(b[pos : pos+2]))
|
|||
pos += 2 |
|||
|
|||
br := bytes.NewReader(b[pos:]) |
|||
for br.Len() > 0 { |
|||
var ext Extension |
|||
ext, err = ReadExtension(br) |
|||
if err != nil { |
|||
return |
|||
} |
|||
h.Extensions = append(h.Extensions, ext) |
|||
} |
|||
return |
|||
} |
|||
|
|||
func (h *ClientHelloHandshake) WriteTo(w io.Writer) (n int64, err error) { |
|||
buf := &bytes.Buffer{} |
|||
buf.WriteByte(ClientHello) |
|||
buf.Write([]byte{0, 0, 0}) // placeholder for payload length
|
|||
binary.Write(buf, binary.BigEndian, h.Version) |
|||
pos := 6 |
|||
binary.Write(buf, binary.BigEndian, h.Random.Time) |
|||
buf.Write(h.Random.Opaque[:]) |
|||
pos += 32 |
|||
buf.WriteByte(byte(len(h.SessionID))) |
|||
buf.Write(h.SessionID) |
|||
pos += (1 + len(h.SessionID)) |
|||
binary.Write(buf, binary.BigEndian, uint16(len(h.CipherSuites)*2)) |
|||
for _, cs := range h.CipherSuites { |
|||
binary.Write(buf, binary.BigEndian, cs) |
|||
} |
|||
pos += (2 + len(h.CipherSuites)*2) |
|||
buf.WriteByte(byte(len(h.CompressionMethods))) |
|||
for _, cm := range h.CompressionMethods { |
|||
buf.WriteByte(byte(cm)) |
|||
} |
|||
pos += (1 + len(h.CompressionMethods)) |
|||
buf.Write([]byte{0, 0}) // placeholder for extensions length
|
|||
|
|||
extLen := 0 |
|||
for _, ext := range h.Extensions { |
|||
nn, _ := buf.Write(ext.Bytes()) |
|||
extLen += nn |
|||
} |
|||
|
|||
b := buf.Bytes() |
|||
plen := len(b) - handshakeHeaderLen |
|||
b[1], b[2], b[3] = byte((plen>>16)&0xFF), byte((plen>>8)&0xFF), byte(plen&0xFF) // payload length
|
|||
b[pos], b[pos+1] = byte((extLen>>8)&0xFF), byte(extLen&0xFF) // extensions length
|
|||
|
|||
nn, err := w.Write(b) |
|||
n = int64(nn) |
|||
return |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
package dissector |
|||
|
|||
import ( |
|||
"bytes" |
|||
"encoding/binary" |
|||
"errors" |
|||
"io" |
|||
) |
|||
|
|||
const ( |
|||
RecordHeaderLen = 5 |
|||
) |
|||
|
|||
const ( |
|||
Handshake = 0x16 |
|||
) |
|||
|
|||
var ( |
|||
ErrBadType = errors.New("bad type") |
|||
) |
|||
|
|||
type Version uint16 |
|||
|
|||
type Record struct { |
|||
Type uint8 |
|||
Version Version |
|||
Opaque []byte |
|||
} |
|||
|
|||
func ReadRecord(r io.Reader) (*Record, error) { |
|||
record := &Record{} |
|||
if _, err := record.ReadFrom(r); err != nil { |
|||
return nil, err |
|||
} |
|||
return record, nil |
|||
} |
|||
|
|||
func (rec *Record) ReadFrom(r io.Reader) (n int64, err error) { |
|||
b := make([]byte, RecordHeaderLen) |
|||
nn, err := io.ReadFull(r, b) |
|||
n += int64(nn) |
|||
if err != nil { |
|||
return |
|||
} |
|||
rec.Type = b[0] |
|||
rec.Version = Version(binary.BigEndian.Uint16(b[1:3])) |
|||
length := int(binary.BigEndian.Uint16(b[3:5])) |
|||
rec.Opaque = make([]byte, length) |
|||
nn, err = io.ReadFull(r, rec.Opaque) |
|||
n += int64(nn) |
|||
return |
|||
} |
|||
|
|||
func (rec *Record) WriteTo(w io.Writer) (n int64, err error) { |
|||
buf := &bytes.Buffer{} |
|||
buf.WriteByte(rec.Type) |
|||
binary.Write(buf, binary.BigEndian, rec.Version) |
|||
binary.Write(buf, binary.BigEndian, uint16(len(rec.Opaque))) |
|||
buf.Write(rec.Opaque) |
|||
return buf.WriteTo(w) |
|||
} |
|||
File diff suppressed because it is too large
Loading…
Reference in new issue