mirror of
https://github.com/cbeuw/Cloak.git
synced 2024-11-19 09:25:41 +00:00
79 lines
2.0 KiB
Go
79 lines
2.0 KiB
Go
package server
|
|
|
|
import (
|
|
"crypto"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/cbeuw/Cloak/internal/ecdh"
|
|
"github.com/cbeuw/Cloak/internal/util"
|
|
"net"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type TLS struct{}
|
|
|
|
var ErrBadClientHello = errors.New("non (or malformed) ClientHello")
|
|
|
|
func (TLS) String() string { return "TLS" }
|
|
func (TLS) HasRecordLayer() bool { return true }
|
|
func (TLS) UnitReadFunc() func(net.Conn, []byte) (int, error) { return util.ReadTLS }
|
|
|
|
func (TLS) handshake(clientHello []byte, privateKey crypto.PrivateKey, originalConn net.Conn) (ai authenticationInfo, finisher func([]byte) (net.Conn, error), err error) {
|
|
var ch *ClientHello
|
|
ch, err = parseClientHello(clientHello)
|
|
if err != nil {
|
|
log.Debug(err)
|
|
err = ErrBadClientHello
|
|
return
|
|
}
|
|
|
|
ai, err = unmarshalClientHello(ch, privateKey)
|
|
if err != nil {
|
|
err = fmt.Errorf("failed to unmarshal ClientHello into authenticationInfo: %v", err)
|
|
return
|
|
}
|
|
|
|
finisher = func(sessionKey []byte) (preparedConn net.Conn, err error) {
|
|
preparedConn = originalConn
|
|
reply, err := composeReply(ch, ai.sharedSecret, sessionKey)
|
|
if err != nil {
|
|
err = fmt.Errorf("failed to compose TLS reply: %v", err)
|
|
return
|
|
}
|
|
_, err = preparedConn.Write(reply)
|
|
if err != nil {
|
|
err = fmt.Errorf("failed to write TLS reply: %v", err)
|
|
go preparedConn.Close()
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func unmarshalClientHello(ch *ClientHello, staticPv crypto.PrivateKey) (ai authenticationInfo, err error) {
|
|
ephPub, ok := ecdh.Unmarshal(ch.random)
|
|
if !ok {
|
|
err = ErrInvalidPubKey
|
|
return
|
|
}
|
|
|
|
ai.nonce = ch.random[:12]
|
|
|
|
ai.sharedSecret = ecdh.GenerateSharedSecret(staticPv, ephPub)
|
|
var keyShare []byte
|
|
keyShare, err = parseKeyShare(ch.extensions[[2]byte{0x00, 0x33}])
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
ai.ciphertextWithTag = append(ch.sessionId, keyShare...)
|
|
if len(ai.ciphertextWithTag) != 64 {
|
|
err = fmt.Errorf("%v: %v", ErrCiphertextLength, len(ai.ciphertextWithTag))
|
|
return
|
|
}
|
|
return
|
|
}
|