Cloak/internal/server/TLS.go

202 lines
5.5 KiB
Go
Raw Normal View History

2018-10-09 15:07:54 +00:00
package server
import (
2019-08-02 00:01:19 +00:00
"bytes"
"crypto/rand"
2018-10-09 15:07:54 +00:00
"encoding/binary"
2019-08-02 00:01:19 +00:00
"encoding/hex"
2018-10-09 15:07:54 +00:00
"errors"
2019-08-02 00:01:19 +00:00
"fmt"
2018-10-09 15:07:54 +00:00
)
// ClientHello contains every field in a ClientHello message
type ClientHello struct {
handshakeType byte
length int
clientVersion []byte
random []byte
sessionIdLen int
sessionId []byte
cipherSuitesLen int
cipherSuites []byte
compressionMethodsLen int
compressionMethods []byte
extensionsLen int
extensions map[[2]byte][]byte
}
2019-01-13 22:22:55 +00:00
var u16 = binary.BigEndian.Uint16
var u32 = binary.BigEndian.Uint32
2018-10-09 15:07:54 +00:00
func parseExtensions(input []byte) (ret map[[2]byte][]byte, err error) {
defer func() {
if r := recover(); r != nil {
err = errors.New("Malformed Extensions")
}
}()
pointer := 0
totalLen := len(input)
ret = make(map[[2]byte][]byte)
for pointer < totalLen {
var typ [2]byte
copy(typ[:], input[pointer:pointer+2])
pointer += 2
2019-01-13 22:22:55 +00:00
length := int(u16(input[pointer : pointer+2]))
2018-10-09 15:07:54 +00:00
pointer += 2
data := input[pointer : pointer+length]
pointer += length
ret[typ] = data
}
return ret, err
}
2019-08-02 00:01:19 +00:00
func parseKeyShare(input []byte) (ret []byte, err error) {
defer func() {
if r := recover(); r != nil {
err = errors.New("malformed key_share")
}
}()
totalLen := int(u16(input[0:2]))
// 2 bytes "client key share length"
pointer := 2
for pointer < totalLen {
if bytes.Equal([]byte{0x00, 0x1d}, input[pointer:pointer+2]) {
// skip "key exchange length"
pointer += 2
length := int(u16(input[pointer : pointer+2]))
pointer += 2
if length != 32 {
return nil, fmt.Errorf("key share length should be 32, instead of %v", length)
}
return input[pointer : pointer+length], nil
}
pointer += 2
length := int(u16(input[pointer : pointer+2]))
pointer += 2
_ = input[pointer : pointer+length]
pointer += length
}
return nil, errors.New("x25519 does not exist")
}
2018-10-09 15:07:54 +00:00
// AddRecordLayer adds record layer to data
func AddRecordLayer(input []byte, typ []byte, ver []byte) []byte {
length := make([]byte, 2)
binary.BigEndian.PutUint16(length, uint16(len(input)))
ret := make([]byte, 5+len(input))
copy(ret[0:1], typ)
copy(ret[1:3], ver)
copy(ret[3:5], length)
copy(ret[5:], input)
return ret
}
// ParseClientHello parses everything on top of the TLS layer
// (including the record layer) into ClientHello type
func ParseClientHello(data []byte) (ret *ClientHello, err error) {
defer func() {
if r := recover(); r != nil {
err = errors.New("Malformed ClientHello")
}
}()
2019-08-03 12:26:57 +00:00
peeled := make([]byte, len(data)-5)
copy(peeled, data[5:])
2018-10-09 15:07:54 +00:00
pointer := 0
// Handshake Type
2019-08-03 12:26:57 +00:00
handshakeType := peeled[pointer]
2018-10-09 15:07:54 +00:00
if handshakeType != 0x01 {
return ret, errors.New("Not a ClientHello")
}
pointer += 1
// Length
2019-08-03 12:26:57 +00:00
length := int(u32(append([]byte{0x00}, peeled[pointer:pointer+3]...)))
2018-10-09 15:07:54 +00:00
pointer += 3
2019-08-03 12:26:57 +00:00
if length != len(peeled[pointer:]) {
2018-10-09 15:07:54 +00:00
return ret, errors.New("Hello length doesn't match")
}
// Client Version
2019-08-03 12:26:57 +00:00
clientVersion := peeled[pointer : pointer+2]
2018-10-09 15:07:54 +00:00
pointer += 2
// Random
2019-08-03 12:26:57 +00:00
random := peeled[pointer : pointer+32]
2018-10-09 15:07:54 +00:00
pointer += 32
// Session ID
2019-08-03 12:26:57 +00:00
sessionIdLen := int(peeled[pointer])
2018-10-09 15:07:54 +00:00
pointer += 1
2019-08-03 12:26:57 +00:00
sessionId := peeled[pointer : pointer+sessionIdLen]
2018-10-09 15:07:54 +00:00
pointer += sessionIdLen
// Cipher Suites
2019-08-03 12:26:57 +00:00
cipherSuitesLen := int(u16(peeled[pointer : pointer+2]))
2018-10-09 15:07:54 +00:00
pointer += 2
2019-08-03 12:26:57 +00:00
cipherSuites := peeled[pointer : pointer+cipherSuitesLen]
2018-10-09 15:07:54 +00:00
pointer += cipherSuitesLen
// Compression Methods
2019-08-03 12:26:57 +00:00
compressionMethodsLen := int(peeled[pointer])
2018-10-09 15:07:54 +00:00
pointer += 1
2019-08-03 12:26:57 +00:00
compressionMethods := peeled[pointer : pointer+compressionMethodsLen]
2018-10-09 15:07:54 +00:00
pointer += compressionMethodsLen
// Extensions
2019-08-03 12:26:57 +00:00
extensionsLen := int(u16(peeled[pointer : pointer+2]))
2018-10-09 15:07:54 +00:00
pointer += 2
2019-08-03 12:26:57 +00:00
extensions, err := parseExtensions(peeled[pointer:])
2018-10-09 15:07:54 +00:00
ret = &ClientHello{
handshakeType,
length,
clientVersion,
random,
sessionIdLen,
sessionId,
cipherSuitesLen,
cipherSuites,
compressionMethodsLen,
compressionMethods,
extensionsLen,
extensions,
}
return
}
2019-08-02 00:01:19 +00:00
func xor(a []byte, b []byte) {
for i := range a {
a[i] ^= b[i]
}
}
func composeServerHello(sessionId []byte, sharedSecret []byte, sessionKey []byte) []byte {
2019-08-02 00:01:19 +00:00
var serverHello [11][]byte
serverHello[0] = []byte{0x02} // handshake type
serverHello[1] = []byte{0x00, 0x00, 0x76} // length 77
serverHello[2] = []byte{0x03, 0x03} // server version
xor(sharedSecret, sessionKey)
serverHello[3] = sharedSecret // random
serverHello[4] = []byte{0x20} // session id length 32
serverHello[5] = sessionId // session id
2019-08-02 00:01:19 +00:00
serverHello[6] = []byte{0xc0, 0x30} // cipher suite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
serverHello[7] = []byte{0x00} // compression method null
serverHello[8] = []byte{0x00, 0x2e} // extensions length 46
keyShare, _ := hex.DecodeString("00330024001d0020")
keyExchange := make([]byte, 32)
rand.Read(keyExchange)
serverHello[9] = append(keyShare, keyExchange...)
serverHello[10], _ = hex.DecodeString("002b00020304")
var ret []byte
for _, s := range serverHello {
ret = append(ret, s...)
2018-10-09 15:07:54 +00:00
}
return ret
}
// ComposeReply composes the ServerHello, ChangeCipherSpec and Finished messages
// together with their respective record layers into one byte slice. The content
// of these messages are random and useless for this plugin
2019-08-02 00:01:19 +00:00
func ComposeReply(ch *ClientHello, sharedSecret []byte, sessionKey []byte) []byte {
2018-10-09 15:07:54 +00:00
TLS12 := []byte{0x03, 0x03}
shBytes := AddRecordLayer(composeServerHello(ch.sessionId, sharedSecret, sessionKey), []byte{0x16}, TLS12)
2018-10-09 15:07:54 +00:00
ccsBytes := AddRecordLayer([]byte{0x01}, []byte{0x14}, TLS12)
ret := append(shBytes, ccsBytes...)
return ret
}