1
1
mirror of https://github.com/wader/fq.git synced 2024-12-29 00:22:38 +03:00
fq/format/tls/rezlib/reinflate.go
Mattias Wadman 9852f56b74 tls: Add TLS 1.0, 1.1, 1.2 decode and decryption
What it can do:
- Decodes records and most standard messages and extensions.
- Decryptes records and reassemples application data stream if a keylog is provided
  and the cipher suite is supported.
- Supports most recommended and used ciphers and a bunch of older ones.

What it can't do:
- SSL v3 maybe supported, is similar to TLS 1.0, not tested.
- Decryption and renegotiation/cipher change.
- Record defragmentation not supported, seems rare over TCP.
- TLS 1.3
- SSL v2 but v2 compat header is supported.
- Some key exchange messages not decoded yet

Decryption code is heavly based on golang crypto/tls and zmap/zcrypto.

Will be base for decoding http2 and other TLS based on protocols.

Fixes #587
2023-03-05 13:52:12 +01:00

91 lines
1.9 KiB
Go

// Package rezlib wraps a zlib reader and makes it possible to read
// until the last current input flush boundary by reading until EOF.
//
// Inspiration from https://github.com/golang/go/issues/48877
//
// TODO: force deflate only?
//
// This is used by TLS deflate (seems be zlib?) where a flush is done
// between each record
package rezlib
import (
"bytes"
"compress/zlib"
"errors"
"fmt"
"io"
)
// max deflate dictionary size
const maxDictSize = 1 << 15 // 32KiB
type Reader struct {
r io.Reader
fr io.Reader
res zlib.Resetter
currentDict bytes.Buffer
zlibHeader [2]byte
hadUnexpectedEOF bool
}
func NewReader(r io.Reader) (*Reader, error) {
var zlibHeader [2]byte
if _, err := io.ReadFull(r, zlibHeader[:]); err != nil {
return nil, err
}
zr, zrErr := zlib.NewReader(io.MultiReader(
bytes.NewBuffer(zlibHeader[:]),
r,
))
if zrErr != nil {
return nil, zrErr
}
res, resOk := zr.(zlib.Resetter)
if !resOk {
panic("zlib reader not a Resetter")
}
return &Reader{
r: r,
fr: zr,
res: res,
zlibHeader: zlibHeader,
}, nil
}
func (r *Reader) Read(b []byte) (int, error) {
if r.hadUnexpectedEOF {
r.hadUnexpectedEOF = false
// inject zlib header again
mr := io.MultiReader(
bytes.NewReader(r.zlibHeader[:]),
r.r,
)
if err := r.res.Reset(mr, r.currentDict.Bytes()); err != nil {
panic(fmt.Sprintf("zlib reader could not reset %s", err))
}
}
n, err := r.fr.Read(b)
r.currentDict.Write(b[:n])
l := r.currentDict.Len()
if l > maxDictSize {
r.currentDict.Next(l - maxDictSize)
}
// TODO: currently we assume ErrUnexpectedEOF means we have read
// until a flush boundary. To get read of the error reset with
// current dictionary
// some better way?
if errors.Is(err, io.ErrUnexpectedEOF) {
r.hadUnexpectedEOF = true
err = io.EOF
}
return n, err
}