2020-10-29 22:47:57 +08:00
|
|
|
package obfs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/hmac"
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"math/rand"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/nadoo/glider/proxy/ssr/internal/ssr"
|
|
|
|
"github.com/nadoo/glider/proxy/ssr/internal/tools"
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
register("tls1.2_ticket_auth", newTLS12TicketAuth)
|
|
|
|
register("tls1.2_ticket_fastauth", newTLS12TicketFastAuth)
|
|
|
|
}
|
|
|
|
|
|
|
|
type tlsAuthData struct {
|
|
|
|
localClientID [32]byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// tls12TicketAuth tls1.2_ticket_auth obfs encapsulate
|
|
|
|
type tls12TicketAuth struct {
|
|
|
|
ssr.ServerInfo
|
|
|
|
data *tlsAuthData
|
|
|
|
handshakeStatus int
|
|
|
|
sendSaver []byte
|
|
|
|
recvBuffer bytes.Buffer
|
|
|
|
fastAuth bool
|
|
|
|
}
|
|
|
|
|
|
|
|
// newTLS12TicketAuth create a tlv1.2_ticket_auth object
|
|
|
|
func newTLS12TicketAuth() IObfs {
|
|
|
|
return &tls12TicketAuth{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// newTLS12TicketFastAuth create a tlv1.2_ticket_fastauth object
|
|
|
|
func newTLS12TicketFastAuth() IObfs {
|
|
|
|
return &tls12TicketAuth{
|
|
|
|
fastAuth: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tls12TicketAuth) SetServerInfo(s *ssr.ServerInfo) {
|
|
|
|
t.ServerInfo = *s
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tls12TicketAuth) GetServerInfo() (s *ssr.ServerInfo) {
|
|
|
|
return &t.ServerInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tls12TicketAuth) SetData(data interface{}) {
|
|
|
|
if auth, ok := data.(*tlsAuthData); ok {
|
|
|
|
t.data = auth
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tls12TicketAuth) GetData() interface{} {
|
|
|
|
if t.data == nil {
|
|
|
|
t.data = &tlsAuthData{}
|
|
|
|
b := make([]byte, 32)
|
|
|
|
|
|
|
|
rand.Read(b)
|
|
|
|
copy(t.data.localClientID[:], b)
|
|
|
|
}
|
|
|
|
return t.data
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tls12TicketAuth) getHost() string {
|
|
|
|
host := t.Host
|
|
|
|
if len(t.Param) > 0 {
|
|
|
|
hosts := strings.Split(t.Param, ",")
|
|
|
|
if len(hosts) > 0 {
|
|
|
|
|
|
|
|
host = hosts[rand.Intn(len(hosts))]
|
|
|
|
host = strings.TrimSpace(host)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(host) > 0 && host[len(host)-1] >= byte('0') && host[len(host)-1] <= byte('9') && len(t.Param) == 0 {
|
|
|
|
host = ""
|
|
|
|
}
|
|
|
|
return host
|
|
|
|
}
|
|
|
|
|
|
|
|
func packData(prefixData []byte, suffixData []byte) (outData []byte) {
|
|
|
|
d := []byte{0x17, 0x3, 0x3, 0, 0}
|
|
|
|
binary.BigEndian.PutUint16(d[3:5], uint16(len(suffixData)&0xFFFF))
|
|
|
|
outData = append(prefixData, d...)
|
|
|
|
outData = append(outData, suffixData...)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tls12TicketAuth) Encode(data []byte) (encodedData []byte, err error) {
|
|
|
|
encodedData = make([]byte, 0)
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
switch t.handshakeStatus {
|
|
|
|
case 8:
|
|
|
|
if len(data) < 1024 {
|
|
|
|
d := []byte{0x17, 0x3, 0x3, 0, 0}
|
|
|
|
binary.BigEndian.PutUint16(d[3:5], uint16(len(data)&0xFFFF))
|
|
|
|
encodedData = append(d, data...)
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
start := 0
|
|
|
|
var l int
|
|
|
|
for len(data)-start > 2048 {
|
|
|
|
l = rand.Intn(4096) + 100
|
|
|
|
if l > len(data)-start {
|
|
|
|
l = len(data) - start
|
|
|
|
}
|
|
|
|
encodedData = packData(encodedData, data[start:start+l])
|
|
|
|
start += l
|
|
|
|
}
|
|
|
|
if len(data)-start > 0 {
|
|
|
|
l = len(data) - start
|
|
|
|
encodedData = packData(encodedData, data[start:start+l])
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
if len(data) > 0 {
|
|
|
|
if len(data) < 1024 {
|
|
|
|
t.sendSaver = packData(t.sendSaver, data)
|
|
|
|
} else {
|
|
|
|
start := 0
|
|
|
|
var l int
|
|
|
|
for len(data)-start > 2048 {
|
|
|
|
l = rand.Intn(4096) + 100
|
|
|
|
if l > len(data)-start {
|
|
|
|
l = len(data) - start
|
|
|
|
}
|
|
|
|
encodedData = packData(encodedData, data[start:start+l])
|
|
|
|
start += l
|
|
|
|
}
|
|
|
|
if len(data)-start > 0 {
|
|
|
|
l = len(data) - start
|
|
|
|
encodedData = packData(encodedData, data[start:start+l])
|
|
|
|
}
|
|
|
|
t.sendSaver = append(t.sendSaver, encodedData...)
|
|
|
|
encodedData = encodedData[:0]
|
|
|
|
}
|
|
|
|
return []byte{}, nil
|
|
|
|
}
|
|
|
|
hmacData := make([]byte, 43)
|
|
|
|
handshakeFinish := []byte("\x14\x03\x03\x00\x01\x01\x16\x03\x03\x00\x20")
|
|
|
|
copy(hmacData, handshakeFinish)
|
|
|
|
rand.Read(hmacData[11:33])
|
|
|
|
h := t.hmacSHA1(hmacData[:33])
|
|
|
|
copy(hmacData[33:], h)
|
|
|
|
encodedData = append(hmacData, t.sendSaver...)
|
|
|
|
t.sendSaver = t.sendSaver[:0]
|
|
|
|
t.handshakeStatus = 8
|
|
|
|
case 0:
|
|
|
|
tlsData0 := []byte("\x00\x1c\xc0\x2b\xc0\x2f\xcc\xa9\xcc\xa8\xcc\x14\xcc\x13\xc0\x0a\xc0\x14\xc0\x09\xc0\x13\x00\x9c\x00\x35\x00\x2f\x00\x0a\x01\x00")
|
|
|
|
tlsData1 := []byte("\xff\x01\x00\x01\x00")
|
|
|
|
tlsData2 := []byte("\x00\x17\x00\x00\x00\x23\x00\xd0")
|
|
|
|
tlsData3 := []byte("\x00\x0d\x00\x16\x00\x14\x06\x01\x06\x03\x05\x01\x05\x03\x04\x01\x04\x03\x03\x01\x03\x03\x02\x01\x02\x03\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x12\x00\x00\x75\x50\x00\x00\x00\x0b\x00\x02\x01\x00\x00\x0a\x00\x06\x00\x04\x00\x17\x00\x18\x00\x15\x00\x66\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
|
|
|
|
|
|
|
|
var tlsData [2048]byte
|
|
|
|
tlsDataLen := 0
|
|
|
|
copy(tlsData[0:], tlsData1)
|
|
|
|
tlsDataLen += len(tlsData1)
|
|
|
|
sni := t.sni(t.getHost())
|
|
|
|
copy(tlsData[tlsDataLen:], sni)
|
|
|
|
tlsDataLen += len(sni)
|
|
|
|
copy(tlsData[tlsDataLen:], tlsData2)
|
|
|
|
tlsDataLen += len(tlsData2)
|
|
|
|
ticketLen := rand.Intn(164)*2 + 64
|
|
|
|
tlsData[tlsDataLen-1] = uint8(ticketLen & 0xff)
|
|
|
|
tlsData[tlsDataLen-2] = uint8(ticketLen >> 8)
|
|
|
|
//ticketLen := 208
|
|
|
|
rand.Read(tlsData[tlsDataLen : tlsDataLen+ticketLen])
|
|
|
|
tlsDataLen += ticketLen
|
|
|
|
copy(tlsData[tlsDataLen:], tlsData3)
|
|
|
|
tlsDataLen += len(tlsData3)
|
|
|
|
|
|
|
|
length := 11 + 32 + 1 + 32 + len(tlsData0) + 2 + tlsDataLen
|
|
|
|
encodedData = make([]byte, length)
|
|
|
|
pdata := length - tlsDataLen
|
|
|
|
l := tlsDataLen
|
|
|
|
copy(encodedData[pdata:], tlsData[:tlsDataLen])
|
|
|
|
encodedData[pdata-1] = uint8(tlsDataLen)
|
|
|
|
encodedData[pdata-2] = uint8(tlsDataLen >> 8)
|
|
|
|
pdata -= 2
|
|
|
|
l += 2
|
|
|
|
copy(encodedData[pdata-len(tlsData0):], tlsData0)
|
|
|
|
pdata -= len(tlsData0)
|
|
|
|
l += len(tlsData0)
|
|
|
|
copy(encodedData[pdata-32:], t.data.localClientID[:])
|
|
|
|
pdata -= 32
|
|
|
|
l += 32
|
|
|
|
encodedData[pdata-1] = 0x20
|
|
|
|
pdata -= 1
|
|
|
|
l += 1
|
|
|
|
copy(encodedData[pdata-32:], t.packAuthData())
|
|
|
|
pdata -= 32
|
|
|
|
l += 32
|
|
|
|
encodedData[pdata-1] = 0x3
|
|
|
|
encodedData[pdata-2] = 0x3 // tls version
|
|
|
|
pdata -= 2
|
|
|
|
l += 2
|
|
|
|
encodedData[pdata-1] = uint8(l)
|
|
|
|
encodedData[pdata-2] = uint8(l >> 8)
|
|
|
|
encodedData[pdata-3] = 0
|
|
|
|
encodedData[pdata-4] = 1
|
|
|
|
pdata -= 4
|
|
|
|
l += 4
|
|
|
|
encodedData[pdata-1] = uint8(l)
|
|
|
|
encodedData[pdata-2] = uint8(l >> 8)
|
|
|
|
pdata -= 2
|
|
|
|
l += 2
|
|
|
|
encodedData[pdata-1] = 0x1
|
|
|
|
encodedData[pdata-2] = 0x3 // tls version
|
|
|
|
pdata -= 2
|
2020-11-07 19:20:35 +08:00
|
|
|
// l += 2
|
2020-10-29 22:47:57 +08:00
|
|
|
encodedData[pdata-1] = 0x16 // tls handshake
|
2020-11-06 22:47:33 +08:00
|
|
|
// pdata -= 1
|
|
|
|
// l += 1
|
2020-10-29 22:47:57 +08:00
|
|
|
|
|
|
|
t.sendSaver = packData(t.sendSaver, data)
|
|
|
|
t.handshakeStatus = 1
|
|
|
|
default:
|
|
|
|
//log.Println(fmt.Errorf("unexpected handshake status: %d", t.handshakeStatus))
|
|
|
|
return nil, fmt.Errorf("unexpected handshake status: %d", t.handshakeStatus)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tls12TicketAuth) Decode(data []byte) (decodedData []byte, needSendBack bool, err error) {
|
|
|
|
if t.handshakeStatus == -1 {
|
|
|
|
return data, false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if t.handshakeStatus == 8 {
|
|
|
|
t.recvBuffer.Write(data)
|
|
|
|
for t.recvBuffer.Len() > 5 {
|
|
|
|
var h [5]byte
|
|
|
|
_, _ = t.recvBuffer.Read(h[:])
|
|
|
|
if !bytes.Equal(h[0:3], []byte{0x17, 0x3, 0x3}) {
|
|
|
|
log.Println("incorrect magic number", h[0:3], ", 0x170303 is expected")
|
|
|
|
return nil, false, ssr.ErrTLS12TicketAuthIncorrectMagicNumber
|
|
|
|
}
|
|
|
|
size := int(binary.BigEndian.Uint16(h[3:5]))
|
|
|
|
if t.recvBuffer.Len() < size {
|
|
|
|
unread := t.recvBuffer.Bytes()
|
|
|
|
t.recvBuffer.Reset()
|
|
|
|
t.recvBuffer.Write(h[:])
|
|
|
|
t.recvBuffer.Write(unread)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
d := make([]byte, size)
|
|
|
|
_, _ = t.recvBuffer.Read(d)
|
|
|
|
decodedData = append(decodedData, d...)
|
|
|
|
}
|
|
|
|
return decodedData, false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(data) < 11+32+1+32 {
|
|
|
|
return nil, false, ssr.ErrTLS12TicketAuthTooShortData
|
|
|
|
}
|
|
|
|
|
|
|
|
hash := t.hmacSHA1(data[11 : 11+22])
|
|
|
|
|
|
|
|
if !hmac.Equal(data[33:33+ssr.ObfsHMACSHA1Len], hash) {
|
|
|
|
return nil, false, ssr.ErrTLS12TicketAuthHMACError
|
|
|
|
}
|
|
|
|
return nil, true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tls12TicketAuth) packAuthData() (outData []byte) {
|
|
|
|
outSize := 32
|
|
|
|
outData = make([]byte, outSize)
|
|
|
|
|
|
|
|
now := time.Now().Unix()
|
|
|
|
binary.BigEndian.PutUint32(outData[0:4], uint32(now))
|
|
|
|
|
|
|
|
rand.Read(outData[4 : 4+18])
|
|
|
|
|
|
|
|
hash := t.hmacSHA1(outData[:outSize-ssr.ObfsHMACSHA1Len])
|
|
|
|
copy(outData[outSize-ssr.ObfsHMACSHA1Len:], hash)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tls12TicketAuth) hmacSHA1(data []byte) []byte {
|
|
|
|
key := make([]byte, t.KeyLen+32)
|
|
|
|
copy(key, t.Key)
|
|
|
|
copy(key[t.KeyLen:], t.data.localClientID[:])
|
|
|
|
|
|
|
|
sha1Data := tools.HmacSHA1(key, data)
|
|
|
|
return sha1Data[:ssr.ObfsHMACSHA1Len]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tls12TicketAuth) sni(u string) []byte {
|
|
|
|
bURL := []byte(u)
|
|
|
|
length := len(bURL)
|
|
|
|
ret := make([]byte, length+9)
|
|
|
|
copy(ret[9:9+length], bURL)
|
|
|
|
binary.BigEndian.PutUint16(ret[7:], uint16(length&0xFFFF))
|
|
|
|
length += 3
|
|
|
|
binary.BigEndian.PutUint16(ret[4:], uint16(length&0xFFFF))
|
|
|
|
length += 2
|
|
|
|
binary.BigEndian.PutUint16(ret[2:], uint16(length&0xFFFF))
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *tls12TicketAuth) GetOverhead() int {
|
|
|
|
return 5
|
|
|
|
}
|