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 {
|
||||
// TODO key exchange phase
|
||||
// TODO server params phase
|
||||
// TODO auth phase
|
||||
c := hs.c
|
||||
hash := hashForSuite(hs.suite)
|
||||
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
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ type clientHandshakeState struct {
|
||||
|
||||
// TLS 1.3 fields
|
||||
keySchedule *keySchedule13
|
||||
privateKey []byte
|
||||
}
|
||||
|
||||
func makeClientHello(config *Config) (*clientHelloMsg, error) {
|
||||
@ -99,6 +100,13 @@ NextCipherSuite:
|
||||
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
|
||||
}
|
||||
|
||||
@ -177,6 +185,19 @@ func (c *Conn) clientHandshake() error {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user