Use AEAD to encrypt session key in ServerHello to provide authentication of the identity of the server

This commit is contained in:
Qian Wang 2019-08-06 23:59:29 +01:00
parent 623ca55ab5
commit 1d878b3adb
3 changed files with 42 additions and 31 deletions

View File

@ -44,7 +44,6 @@ func composeClientHello(sta *State) ([]byte, []byte) {
} }
func PrepareConnection(sta *State, conn net.Conn) (sessionKey []byte, err error) { func PrepareConnection(sta *State, conn net.Conn) (sessionKey []byte, err error) {
clientHello, sharedSecret := composeClientHello(sta) clientHello, sharedSecret := composeClientHello(sta)
_, err = conn.Write(clientHello) _, err = conn.Write(clientHello)
if err != nil { if err != nil {
@ -58,8 +57,15 @@ func PrepareConnection(sta *State, conn net.Conn) (sessionKey []byte, err error)
if err != nil { if err != nil {
return return
} }
serverRandom := buf[11:43]
sessionKey = decryptSessionKey(serverRandom, sharedSecret) encrypted := append(buf[11:43], buf[89:121]...)
nonce := encrypted[0:12]
ciphertext := encrypted[12:60]
sessionKey, err = util.AESGCMDecrypt(nonce, sharedSecret, ciphertext)
if err != nil {
return
}
_, err = util.ReadTLS(conn, buf) _, err = util.ReadTLS(conn, buf)
if err != nil { if err != nil {
return return

View File

@ -28,14 +28,3 @@ func makeHiddenData(sta *State) (random, TLSsessionID, keyShare, sharedSecret []
keyShare = ciphertext[32:64] keyShare = ciphertext[32:64]
return return
} }
func xor(a []byte, b []byte) {
for i := range a {
a[i] ^= b[i]
}
}
func decryptSessionKey(serverRandom []byte, sharedSecret []byte) []byte {
xor(serverRandom, sharedSecret)
return serverRandom
}

View File

@ -7,6 +7,7 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"github.com/cbeuw/Cloak/internal/util"
"net" "net"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -166,13 +167,20 @@ func xor(a []byte, b []byte) {
} }
} }
func composeServerHello(sessionId []byte, sharedSecret []byte, sessionKey []byte) []byte { func composeServerHello(sessionId []byte, sharedSecret []byte, sessionKey []byte) ([]byte, error) {
nonce := make([]byte, 12)
rand.Read(nonce)
encryptedKey, err := util.AESGCMEncrypt(nonce, sharedSecret, sessionKey) // 32 + 16 = 48 bytes
if err != nil {
return nil, err
}
var serverHello [11][]byte var serverHello [11][]byte
serverHello[0] = []byte{0x02} // handshake type serverHello[0] = []byte{0x02} // handshake type
serverHello[1] = []byte{0x00, 0x00, 0x76} // length 77 serverHello[1] = []byte{0x00, 0x00, 0x76} // length 77
serverHello[2] = []byte{0x03, 0x03} // server version serverHello[2] = []byte{0x03, 0x03} // server version
xor(sharedSecret, sessionKey) serverHello[3] = append(nonce[0:12], encryptedKey[0:20]...) // random 32 bytes
serverHello[3] = sharedSecret // random
serverHello[4] = []byte{0x20} // session id length 32 serverHello[4] = []byte{0x20} // session id length 32
serverHello[5] = sessionId // session id serverHello[5] = sessionId // session id
serverHello[6] = []byte{0xc0, 0x30} // cipher suite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 serverHello[6] = []byte{0xc0, 0x30} // cipher suite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
@ -181,7 +189,8 @@ func composeServerHello(sessionId []byte, sharedSecret []byte, sessionKey []byte
keyShare, _ := hex.DecodeString("00330024001d0020") keyShare, _ := hex.DecodeString("00330024001d0020")
keyExchange := make([]byte, 32) keyExchange := make([]byte, 32)
rand.Read(keyExchange) copy(keyExchange, encryptedKey[20:48])
rand.Read(keyExchange[28:32])
serverHello[9] = append(keyShare, keyExchange...) serverHello[9] = append(keyShare, keyExchange...)
serverHello[10], _ = hex.DecodeString("002b00020304") serverHello[10], _ = hex.DecodeString("002b00020304")
@ -189,18 +198,22 @@ func composeServerHello(sessionId []byte, sharedSecret []byte, sessionKey []byte
for _, s := range serverHello { for _, s := range serverHello {
ret = append(ret, s...) ret = append(ret, s...)
} }
return ret return ret, nil
} }
// composeReply composes the ServerHello, ChangeCipherSpec and Finished messages // composeReply composes the ServerHello, ChangeCipherSpec and Finished messages
// together with their respective record layers into one byte slice. The content // together with their respective record layers into one byte slice. The content
// of these messages are random and useless for this plugin // of these messages are random and useless for this plugin
func composeReply(ch *ClientHello, sharedSecret []byte, sessionKey []byte) []byte { func composeReply(ch *ClientHello, sharedSecret []byte, sessionKey []byte) ([]byte, error) {
TLS12 := []byte{0x03, 0x03} TLS12 := []byte{0x03, 0x03}
shBytes := addRecordLayer(composeServerHello(ch.sessionId, sharedSecret, sessionKey), []byte{0x16}, TLS12) sh, err := composeServerHello(ch.sessionId, sharedSecret, sessionKey)
if err != nil {
return nil, err
}
shBytes := addRecordLayer(sh, []byte{0x16}, TLS12)
ccsBytes := addRecordLayer([]byte{0x01}, []byte{0x14}, TLS12) ccsBytes := addRecordLayer([]byte{0x01}, []byte{0x14}, TLS12)
ret := append(shBytes, ccsBytes...) ret := append(shBytes, ccsBytes...)
return ret return ret, nil
} }
var ErrBadClientHello = errors.New("non (or malformed) ClientHello") var ErrBadClientHello = errors.New("non (or malformed) ClientHello")
@ -228,7 +241,10 @@ func PrepareConnection(firstPacket []byte, sta *State, conn net.Conn) (UID []byt
} }
finisher = func(sessionKey []byte) error { finisher = func(sessionKey []byte) error {
reply := composeReply(ch, sharedSecret, sessionKey) reply, err := composeReply(ch, sharedSecret, sessionKey)
if err != nil {
return err
}
_, err = conn.Write(reply) _, err = conn.Write(reply)
if err != nil { if err != nil {
go conn.Close() go conn.Close()