crypto/tls: initial TLS 1.3 client support
Advertise TLS 1.3 in supported_versions and send a key share for the first preferred curve. Missing are HRR, certificate validation and Encrypted Extensions processing (see TODO notes). For simplicity only a single key share is remembered. This key share should be updated with a HRR (when implemented).
This commit is contained in:
parent
634f9a5858
commit
9e25a0a25d
120
13.go
120
13.go
@ -737,8 +737,122 @@ func (hs *serverHandshakeState) traceErr(err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (hs *clientHandshakeState) doTLS13Handshake() error {
|
func (hs *clientHandshakeState) doTLS13Handshake() error {
|
||||||
// TODO key exchange phase
|
c := hs.c
|
||||||
// TODO server params phase
|
hash := hashForSuite(hs.suite)
|
||||||
// TODO auth phase
|
hashSize := hash.Size()
|
||||||
|
serverHello := hs.serverHello
|
||||||
|
// TODO check if keyshare is unacceptable, raise HRR.
|
||||||
|
|
||||||
|
clientKS := hs.hello.keyShares[0]
|
||||||
|
if serverHello.keyShare.group != clientKS.group {
|
||||||
|
c.sendAlert(alertIllegalParameter)
|
||||||
|
return errors.New("bad or missing key share from server")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0-RTT is not supported yet, so use an empty PSK.
|
||||||
|
hs.keySchedule.setSecret(nil)
|
||||||
|
ecdheSecret := deriveECDHESecret(serverHello.keyShare, hs.privateKey)
|
||||||
|
if ecdheSecret == nil {
|
||||||
|
c.sendAlert(alertIllegalParameter)
|
||||||
|
return errors.New("tls: bad ECDHE server share")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate handshake secrets.
|
||||||
|
hs.keySchedule.setSecret(ecdheSecret)
|
||||||
|
clientCipher, clientHandshakeSecret := hs.keySchedule.prepareCipher(secretHandshakeClient)
|
||||||
|
serverCipher, serverHandshakeSecret := hs.keySchedule.prepareCipher(secretHandshakeServer)
|
||||||
|
if c.hand.Len() > 0 {
|
||||||
|
c.sendAlert(alertUnexpectedMessage)
|
||||||
|
return errors.New("tls: unexpected data after Server Hello")
|
||||||
|
}
|
||||||
|
// Do not change the sender key yet, the server must authenticate first.
|
||||||
|
c.in.setCipher(c.vers, serverCipher)
|
||||||
|
|
||||||
|
// Calculate MAC key for Finished messages.
|
||||||
|
serverFinishedKey := hkdfExpandLabel(hash, serverHandshakeSecret, nil, "finished", hashSize)
|
||||||
|
clientFinishedKey := hkdfExpandLabel(hash, clientHandshakeSecret, nil, "finished", hashSize)
|
||||||
|
|
||||||
|
msg, err := c.readHandshake()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
|
||||||
|
if !ok {
|
||||||
|
c.sendAlert(alertUnexpectedMessage)
|
||||||
|
return unexpectedMessageError(encryptedExtensions, msg)
|
||||||
|
}
|
||||||
|
hs.keySchedule.write(encryptedExtensions.marshal())
|
||||||
|
// TODO process encryptedExtensions
|
||||||
|
|
||||||
|
// PSKs are not supported, so receive Certificate message.
|
||||||
|
msg, err = c.readHandshake()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// TODO handle optional CertificateRequest
|
||||||
|
certMsg, ok := msg.(*certificateMsg13)
|
||||||
|
if !ok {
|
||||||
|
c.sendAlert(alertUnexpectedMessage)
|
||||||
|
return unexpectedMessageError(certMsg, msg)
|
||||||
|
}
|
||||||
|
hs.keySchedule.write(certMsg.marshal())
|
||||||
|
// TODO process Certificate
|
||||||
|
|
||||||
|
// Receive CertificateVerify message.
|
||||||
|
msg, err = c.readHandshake()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
certVerifyMsg, ok := msg.(*certificateVerifyMsg)
|
||||||
|
if !ok {
|
||||||
|
c.sendAlert(alertUnexpectedMessage)
|
||||||
|
return unexpectedMessageError(certVerifyMsg, msg)
|
||||||
|
}
|
||||||
|
// TODO process CertificateVerify
|
||||||
|
hs.keySchedule.write(certVerifyMsg.marshal())
|
||||||
|
|
||||||
|
// Receive Finished message.
|
||||||
|
msg, err = c.readHandshake()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
serverFinished, ok := msg.(*finishedMsg)
|
||||||
|
if !ok {
|
||||||
|
c.sendAlert(alertUnexpectedMessage)
|
||||||
|
return unexpectedMessageError(serverFinished, msg)
|
||||||
|
}
|
||||||
|
// Validate server Finished hash.
|
||||||
|
expectedVerifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, serverFinishedKey)
|
||||||
|
if subtle.ConstantTimeCompare(expectedVerifyData, serverFinished.verifyData) != 1 {
|
||||||
|
c.sendAlert(alertDecryptError)
|
||||||
|
return errors.New("tls: server's Finished message is incorrect")
|
||||||
|
}
|
||||||
|
hs.keySchedule.write(serverFinished.marshal())
|
||||||
|
|
||||||
|
// Server has authenticated itself, change our cipher.
|
||||||
|
c.out.setCipher(c.vers, clientCipher)
|
||||||
|
|
||||||
|
// TODO optionally send a client cert
|
||||||
|
|
||||||
|
// Send Finished
|
||||||
|
verifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, clientFinishedKey)
|
||||||
|
clientFinished := &finishedMsg{
|
||||||
|
verifyData: verifyData,
|
||||||
|
}
|
||||||
|
if _, err := c.writeRecord(recordTypeHandshake, clientFinished.marshal()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate application traffic secrets.
|
||||||
|
hs.keySchedule.setSecret(nil) // derive master secret
|
||||||
|
// TODO store initial traffic secret key for KeyUpdate
|
||||||
|
clientCipher, _ = hs.keySchedule.prepareCipher(secretApplicationClient)
|
||||||
|
serverCipher, _ = hs.keySchedule.prepareCipher(secretApplicationServer)
|
||||||
|
c.out.setCipher(c.vers, clientCipher)
|
||||||
|
if c.hand.Len() > 0 {
|
||||||
|
c.sendAlert(alertUnexpectedMessage)
|
||||||
|
return errors.New("tls: unexpected data after handshake")
|
||||||
|
}
|
||||||
|
c.in.setCipher(c.vers, serverCipher)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ type clientHandshakeState struct {
|
|||||||
|
|
||||||
// TLS 1.3 fields
|
// TLS 1.3 fields
|
||||||
keySchedule *keySchedule13
|
keySchedule *keySchedule13
|
||||||
|
privateKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeClientHello(config *Config) (*clientHelloMsg, error) {
|
func makeClientHello(config *Config) (*clientHelloMsg, error) {
|
||||||
@ -99,6 +100,13 @@ NextCipherSuite:
|
|||||||
hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms
|
hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hello.vers >= VersionTLS13 {
|
||||||
|
// Version preference is indicated via "supported_extensions",
|
||||||
|
// set legacy_version to TLS 1.2 for backwards compatibility.
|
||||||
|
hello.vers = VersionTLS12
|
||||||
|
hello.supportedVersions = config.getSupportedVersions()
|
||||||
|
}
|
||||||
|
|
||||||
return hello, nil
|
return hello, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,6 +185,19 @@ func (c *Conn) clientHandshake() error {
|
|||||||
session: session,
|
session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var clientKS keyShare
|
||||||
|
if c.config.maxVersion() >= VersionTLS13 {
|
||||||
|
// Create one keyshare for the first default curve. If it is not
|
||||||
|
// appropriate, the server should raise a HRR.
|
||||||
|
defaultGroup := c.config.curvePreferences()[0]
|
||||||
|
hs.privateKey, clientKS, err = c.config.generateKeyShare(defaultGroup)
|
||||||
|
if err != nil {
|
||||||
|
c.sendAlert(alertInternalError)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hello.keyShares = []keyShare{clientKS}
|
||||||
|
}
|
||||||
|
|
||||||
if err = hs.handshake(); err != nil {
|
if err = hs.handshake(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user