Cloak/internal/server/TLS.go

79 lines
2.0 KiB
Go
Raw Normal View History

2018-10-09 15:07:54 +00:00
package server
import (
2019-08-31 20:40:50 +00:00
"crypto"
2018-10-09 15:07:54 +00:00
"errors"
2019-08-02 00:01:19 +00:00
"fmt"
2019-08-31 20:40:50 +00:00
"github.com/cbeuw/Cloak/internal/ecdh"
"github.com/cbeuw/Cloak/internal/util"
2020-01-22 18:37:01 +00:00
"net"
2018-10-09 15:07:54 +00:00
2020-01-22 18:37:01 +00:00
log "github.com/sirupsen/logrus"
)
2019-08-02 00:01:19 +00:00
2020-01-22 18:37:01 +00:00
type TLS struct{}
2018-10-09 15:07:54 +00:00
2020-01-22 18:37:01 +00:00
var ErrBadClientHello = errors.New("non (or malformed) ClientHello")
2019-08-03 12:26:57 +00:00
2020-01-22 18:37:01 +00:00
func (TLS) String() string { return "TLS" }
func (TLS) HasRecordLayer() bool { return true }
func (TLS) UnitReadFunc() func(net.Conn, []byte) (int, error) { return util.ReadTLS }
2020-01-22 18:37:01 +00:00
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
2018-10-09 15:07:54 +00:00
}
2020-01-22 18:37:01 +00:00
ai, err = unmarshalClientHello(ch, privateKey)
if err != nil {
2020-01-22 18:37:01 +00:00
err = fmt.Errorf("failed to unmarshal ClientHello into authenticationInfo: %v", err)
return
}
2020-01-22 18:37:01 +00:00
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
2018-10-09 15:07:54 +00:00
}
2020-01-22 18:37:01 +00:00
return
2018-10-09 15:07:54 +00:00
}
2019-08-06 14:50:33 +00:00
2019-08-31 20:40:50 +00:00
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
}