package tls
import (
"crypto/elliptic"
"crypto/hmac"
"errors"
"hash"
"io"
"math/big"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/curve25519"
"golang.org/x/crypto/hkdf"
)
const (
resumptionBinderLabel = "res binder"
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 )
})
out := make ([]byte , length )
n , err := hkdf .Expand (c .hash .New , secret , hkdfLabel .BytesOrPanic ()).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
}
}
type ecdheParameters interface {
CurveID () CurveID
PublicKey () []byte
SharedKey (peerPublicKey []byte ) []byte
}
func generateECDHEParameters (rand io .Reader , curveID CurveID ) (ecdheParameters , error ) {
if curveID == X25519 {
privateKey := make ([]byte , curve25519 .ScalarSize )
if _ , err := io .ReadFull (rand , privateKey ); err != nil {
return nil , err
}
publicKey , err := curve25519 .X25519 (privateKey , curve25519 .Basepoint )
if err != nil {
return nil , err
}
return &x25519Parameters {privateKey : privateKey , publicKey : publicKey }, nil
}
curve , ok := curveForCurveID (curveID )
if !ok {
return nil , errors .New ("tls: internal error: unsupported curve" )
}
p := &nistParameters {curveID : curveID }
var err error
p .privateKey , p .x , p .y , err = elliptic .GenerateKey (curve , rand )
if err != nil {
return nil , err
}
return p , nil
}
func curveForCurveID (id CurveID ) (elliptic .Curve , bool ) {
switch id {
case CurveP256 :
return elliptic .P256 (), true
case CurveP384 :
return elliptic .P384 (), true
case CurveP521 :
return elliptic .P521 (), true
default :
return nil , false
}
}
type nistParameters struct {
privateKey []byte
x, y *big .Int
curveID CurveID
}
func (p *nistParameters ) CurveID () CurveID {
return p .curveID
}
func (p *nistParameters ) PublicKey () []byte {
curve , _ := curveForCurveID (p .curveID )
return elliptic .Marshal (curve , p .x , p .y )
}
func (p *nistParameters ) SharedKey (peerPublicKey []byte ) []byte {
curve , _ := curveForCurveID (p .curveID )
x , y := elliptic .Unmarshal (curve , peerPublicKey )
if x == nil {
return nil
}
xShared , _ := curve .ScalarMult (x , y , p .privateKey )
sharedKey := make ([]byte , (curve .Params ().BitSize +7 )/8 )
return xShared .FillBytes (sharedKey )
}
type x25519Parameters struct {
privateKey []byte
publicKey []byte
}
func (p *x25519Parameters ) CurveID () CurveID {
return X25519
}
func (p *x25519Parameters ) PublicKey () []byte {
return p .publicKey [:]
}
func (p *x25519Parameters ) SharedKey (peerPublicKey []byte ) []byte {
sharedKey , err := curve25519 .X25519 (p .privateKey , peerPublicKey )
if err != nil {
return nil
}
return sharedKey
}
The pages are generated with Golds v0.3.6 . (GOOS=darwin 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 .