package tls
import (
"crypto/ecdh"
"crypto/hmac"
"errors"
"fmt"
"hash"
"io"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/hkdf"
)
const (
resumptionBinderLabel = "res binder"
clientEarlyTrafficLabel = "c e traffic"
clientHandshakeTrafficLabel = "c hs traffic"
serverHandshakeTrafficLabel = "s hs traffic"
clientApplicationTrafficLabel = "c ap traffic"
serverApplicationTrafficLabel = "s ap traffic"
exporterLabel = "exp master"
resumptionLabel = "res master"
trafficUpdateLabel = "traffic upd"
)
func (c *cipherSuiteTLS13 ) expandLabel (secret []byte , label string , context []byte , length int ) []byte {
var hkdfLabel cryptobyte .Builder
hkdfLabel .AddUint16 (uint16 (length ))
hkdfLabel .AddUint8LengthPrefixed (func (b *cryptobyte .Builder ) {
b .AddBytes ([]byte ("tls13 " ))
b .AddBytes ([]byte (label ))
})
hkdfLabel .AddUint8LengthPrefixed (func (b *cryptobyte .Builder ) {
b .AddBytes (context )
})
hkdfLabelBytes , err := hkdfLabel .Bytes ()
if err != nil {
panic (fmt .Errorf ("failed to construct HKDF label: %s" , err ))
}
out := make ([]byte , length )
n , err := hkdf .Expand (c .hash .New , secret , hkdfLabelBytes ).Read (out )
if err != nil || n != length {
panic ("tls: HKDF-Expand-Label invocation failed unexpectedly" )
}
return out
}
func (c *cipherSuiteTLS13 ) deriveSecret (secret []byte , label string , transcript hash .Hash ) []byte {
if transcript == nil {
transcript = c .hash .New ()
}
return c .expandLabel (secret , label , transcript .Sum (nil ), c .hash .Size ())
}
func (c *cipherSuiteTLS13 ) extract (newSecret , currentSecret []byte ) []byte {
if newSecret == nil {
newSecret = make ([]byte , c .hash .Size ())
}
return hkdf .Extract (c .hash .New , newSecret , currentSecret )
}
func (c *cipherSuiteTLS13 ) nextTrafficSecret (trafficSecret []byte ) []byte {
return c .expandLabel (trafficSecret , trafficUpdateLabel , nil , c .hash .Size ())
}
func (c *cipherSuiteTLS13 ) trafficKey (trafficSecret []byte ) (key , iv []byte ) {
key = c .expandLabel (trafficSecret , "key" , nil , c .keyLen )
iv = c .expandLabel (trafficSecret , "iv" , nil , aeadNonceLength )
return
}
func (c *cipherSuiteTLS13 ) finishedHash (baseKey []byte , transcript hash .Hash ) []byte {
finishedKey := c .expandLabel (baseKey , "finished" , nil , c .hash .Size ())
verifyData := hmac .New (c .hash .New , finishedKey )
verifyData .Write (transcript .Sum (nil ))
return verifyData .Sum (nil )
}
func (c *cipherSuiteTLS13 ) exportKeyingMaterial (masterSecret []byte , transcript hash .Hash ) func (string , []byte , int ) ([]byte , error ) {
expMasterSecret := c .deriveSecret (masterSecret , exporterLabel , transcript )
return func (label string , context []byte , length int ) ([]byte , error ) {
secret := c .deriveSecret (expMasterSecret , label , nil )
h := c .hash .New ()
h .Write (context )
return c .expandLabel (secret , "exporter" , h .Sum (nil ), length ), nil
}
}
func generateECDHEKey (rand io .Reader , curveID CurveID ) (*ecdh .PrivateKey , error ) {
curve , ok := curveForCurveID (curveID )
if !ok {
return nil , errors .New ("tls: internal error: unsupported curve" )
}
return curve .GenerateKey (rand )
}
func curveForCurveID (id CurveID ) (ecdh .Curve , bool ) {
switch id {
case X25519 :
return ecdh .X25519 (), true
case CurveP256 :
return ecdh .P256 (), true
case CurveP384 :
return ecdh .P384 (), true
case CurveP521 :
return ecdh .P521 (), true
default :
return nil , false
}
}
func curveIDForCurve (curve ecdh .Curve ) (CurveID , bool ) {
switch curve {
case ecdh .X25519 ():
return X25519 , true
case ecdh .P256 ():
return CurveP256 , true
case ecdh .P384 ():
return CurveP384 , true
case ecdh .P521 ():
return CurveP521 , true
default :
return 0 , false
}
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .