key_schedule.mx raw

   1  // Copyright 2018 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package tls
   6  
   7  import (
   8  	"crypto"
   9  	"crypto/ecdh"
  10  	"crypto/hmac"
  11  	"crypto/internal/fips140/tls13"
  12  	"crypto/mlkem"
  13  	"errors"
  14  	"hash"
  15  	"io"
  16  )
  17  
  18  // This file contains the functions necessary to compute the TLS 1.3 key
  19  // schedule. See RFC 8446, Section 7.
  20  
  21  // nextTrafficSecret generates the next traffic secret, given the current one,
  22  // according to RFC 8446, Section 7.2.
  23  func (c *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte {
  24  	return tls13.ExpandLabel(c.hash.New, trafficSecret, "traffic upd", nil, c.hash.Size())
  25  }
  26  
  27  // trafficKey generates traffic keys according to RFC 8446, Section 7.3.
  28  func (c *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) {
  29  	key = tls13.ExpandLabel(c.hash.New, trafficSecret, "key", nil, c.keyLen)
  30  	iv = tls13.ExpandLabel(c.hash.New, trafficSecret, "iv", nil, aeadNonceLength)
  31  	return
  32  }
  33  
  34  // finishedHash generates the Finished verify_data or PskBinderEntry according
  35  // to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey
  36  // selection.
  37  func (c *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte {
  38  	finishedKey := tls13.ExpandLabel(c.hash.New, baseKey, "finished", nil, c.hash.Size())
  39  	verifyData := hmac.New(c.hash.New, finishedKey)
  40  	verifyData.Write(transcript.Sum(nil))
  41  	return verifyData.Sum(nil)
  42  }
  43  
  44  // exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to
  45  // RFC 8446, Section 7.5.
  46  func (c *cipherSuiteTLS13) exportKeyingMaterial(s *tls13.MasterSecret, transcript hash.Hash) func([]byte, []byte, int) ([]byte, error) {
  47  	expMasterSecret := s.ExporterMasterSecret(transcript)
  48  	return func(label []byte, context []byte, length int) ([]byte, error) {
  49  		return expMasterSecret.Exporter(label, context, length), nil
  50  	}
  51  }
  52  
  53  type keySharePrivateKeys struct {
  54  	ecdhe *ecdh.PrivateKey
  55  	mlkem crypto.Decapsulator
  56  }
  57  
  58  // A keyExchange implements a TLS 1.3 KEM.
  59  type keyExchange interface {
  60  	// keyShares generates one or two key shares.
  61  	//
  62  	// The first one will match the id, the second (if present) reuses the
  63  	// traditional component of the requested hybrid, as allowed by
  64  	// draft-ietf-tls-hybrid-design-09, Section 3.2.
  65  	keyShares(rand io.Reader) (*keySharePrivateKeys, []keyShare, error)
  66  
  67  	// serverSharedSecret computes the shared secret and the server's key share.
  68  	serverSharedSecret(rand io.Reader, clientKeyShare []byte) ([]byte, keyShare, error)
  69  
  70  	// clientSharedSecret computes the shared secret given the server's key
  71  	// share and the keys generated by keyShares.
  72  	clientSharedSecret(priv *keySharePrivateKeys, serverKeyShare []byte) ([]byte, error)
  73  }
  74  
  75  func keyExchangeForCurveID(id CurveID) (keyExchange, error) {
  76  	newMLKEMPrivateKey768 := func(b []byte) (crypto.Decapsulator, error) {
  77  		return mlkem.NewDecapsulationKey768(b)
  78  	}
  79  	newMLKEMPrivateKey1024 := func(b []byte) (crypto.Decapsulator, error) {
  80  		return mlkem.NewDecapsulationKey1024(b)
  81  	}
  82  	newMLKEMPublicKey768 := func(b []byte) (crypto.Encapsulator, error) {
  83  		return mlkem.NewEncapsulationKey768(b)
  84  	}
  85  	newMLKEMPublicKey1024 := func(b []byte) (crypto.Encapsulator, error) {
  86  		return mlkem.NewEncapsulationKey1024(b)
  87  	}
  88  	switch id {
  89  	case X25519:
  90  		return &ecdhKeyExchange{id, ecdh.X25519()}, nil
  91  	case CurveP256:
  92  		return &ecdhKeyExchange{id, ecdh.P256()}, nil
  93  	case CurveP384:
  94  		return &ecdhKeyExchange{id, ecdh.P384()}, nil
  95  	case CurveP521:
  96  		return &ecdhKeyExchange{id, ecdh.P521()}, nil
  97  	case X25519MLKEM768:
  98  		return &hybridKeyExchange{id, ecdhKeyExchange{X25519, ecdh.X25519()},
  99  			32, mlkem.EncapsulationKeySize768, mlkem.CiphertextSize768,
 100  			newMLKEMPrivateKey768, newMLKEMPublicKey768}, nil
 101  	case SecP256r1MLKEM768:
 102  		return &hybridKeyExchange{id, ecdhKeyExchange{CurveP256, ecdh.P256()},
 103  			65, mlkem.EncapsulationKeySize768, mlkem.CiphertextSize768,
 104  			newMLKEMPrivateKey768, newMLKEMPublicKey768}, nil
 105  	case SecP384r1MLKEM1024:
 106  		return &hybridKeyExchange{id, ecdhKeyExchange{CurveP384, ecdh.P384()},
 107  			97, mlkem.EncapsulationKeySize1024, mlkem.CiphertextSize1024,
 108  			newMLKEMPrivateKey1024, newMLKEMPublicKey1024}, nil
 109  	default:
 110  		return nil, errors.New("tls: unsupported key exchange")
 111  	}
 112  }
 113  
 114  type ecdhKeyExchange struct {
 115  	id    CurveID
 116  	curve ecdh.Curve
 117  }
 118  
 119  func (ke *ecdhKeyExchange) keyShares(rand io.Reader) (*keySharePrivateKeys, []keyShare, error) {
 120  	priv, err := ke.curve.GenerateKey(rand)
 121  	if err != nil {
 122  		return nil, nil, err
 123  	}
 124  	return &keySharePrivateKeys{ecdhe: priv}, []keyShare{{ke.id, priv.PublicKey().Bytes()}}, nil
 125  }
 126  
 127  func (ke *ecdhKeyExchange) serverSharedSecret(rand io.Reader, clientKeyShare []byte) ([]byte, keyShare, error) {
 128  	key, err := ke.curve.GenerateKey(rand)
 129  	if err != nil {
 130  		return nil, keyShare{}, err
 131  	}
 132  	peerKey, err := ke.curve.NewPublicKey(clientKeyShare)
 133  	if err != nil {
 134  		return nil, keyShare{}, err
 135  	}
 136  	sharedKey, err := key.ECDH(peerKey)
 137  	if err != nil {
 138  		return nil, keyShare{}, err
 139  	}
 140  	return sharedKey, keyShare{ke.id, key.PublicKey().Bytes()}, nil
 141  }
 142  
 143  func (ke *ecdhKeyExchange) clientSharedSecret(priv *keySharePrivateKeys, serverKeyShare []byte) ([]byte, error) {
 144  	peerKey, err := ke.curve.NewPublicKey(serverKeyShare)
 145  	if err != nil {
 146  		return nil, err
 147  	}
 148  	sharedKey, err := priv.ecdhe.ECDH(peerKey)
 149  	if err != nil {
 150  		return nil, err
 151  	}
 152  	return sharedKey, nil
 153  }
 154  
 155  type hybridKeyExchange struct {
 156  	id   CurveID
 157  	ecdh ecdhKeyExchange
 158  
 159  	ecdhElementSize     int
 160  	mlkemPublicKeySize  int
 161  	mlkemCiphertextSize int
 162  
 163  	newMLKEMPrivateKey func([]byte) (crypto.Decapsulator, error)
 164  	newMLKEMPublicKey  func([]byte) (crypto.Encapsulator, error)
 165  }
 166  
 167  func (ke *hybridKeyExchange) keyShares(rand io.Reader) (*keySharePrivateKeys, []keyShare, error) {
 168  	priv, ecdhShares, err := ke.ecdh.keyShares(rand)
 169  	if err != nil {
 170  		return nil, nil, err
 171  	}
 172  	seed := []byte{:mlkem.SeedSize}
 173  	if _, err := io.ReadFull(rand, seed); err != nil {
 174  		return nil, nil, err
 175  	}
 176  	priv.mlkem, err = ke.newMLKEMPrivateKey(seed)
 177  	if err != nil {
 178  		return nil, nil, err
 179  	}
 180  	var shareData []byte
 181  	// For X25519MLKEM768, the ML-KEM-768 encapsulation key comes first.
 182  	// For SecP256r1MLKEM768 and SecP384r1MLKEM1024, the ECDH share comes first.
 183  	// See draft-ietf-tls-ecdhe-mlkem-02, Section 4.1.
 184  	if ke.id == X25519MLKEM768 {
 185  		shareData = append(priv.mlkem.Encapsulator().Bytes(), ecdhShares[0].data...)
 186  	} else {
 187  		shareData = append(ecdhShares[0].data, priv.mlkem.Encapsulator().Bytes()...)
 188  	}
 189  	return priv, []keyShare{{ke.id, shareData}, ecdhShares[0]}, nil
 190  }
 191  
 192  func (ke *hybridKeyExchange) serverSharedSecret(rand io.Reader, clientKeyShare []byte) ([]byte, keyShare, error) {
 193  	if len(clientKeyShare) != ke.ecdhElementSize+ke.mlkemPublicKeySize {
 194  		return nil, keyShare{}, errors.New("tls: invalid client key share length for hybrid key exchange")
 195  	}
 196  	var ecdhShareData, mlkemShareData []byte
 197  	if ke.id == X25519MLKEM768 {
 198  		mlkemShareData = clientKeyShare[:ke.mlkemPublicKeySize]
 199  		ecdhShareData = clientKeyShare[ke.mlkemPublicKeySize:]
 200  	} else {
 201  		ecdhShareData = clientKeyShare[:ke.ecdhElementSize]
 202  		mlkemShareData = clientKeyShare[ke.ecdhElementSize:]
 203  	}
 204  	ecdhSharedSecret, ks, err := ke.ecdh.serverSharedSecret(rand, ecdhShareData)
 205  	if err != nil {
 206  		return nil, keyShare{}, err
 207  	}
 208  	mlkemPeerKey, err := ke.newMLKEMPublicKey(mlkemShareData)
 209  	if err != nil {
 210  		return nil, keyShare{}, err
 211  	}
 212  	mlkemSharedSecret, mlkemKeyShare := mlkemPeerKey.Encapsulate()
 213  	var sharedKey []byte
 214  	if ke.id == X25519MLKEM768 {
 215  		sharedKey = append(mlkemSharedSecret, ecdhSharedSecret...)
 216  		ks.data = append(mlkemKeyShare, ks.data...)
 217  	} else {
 218  		sharedKey = append(ecdhSharedSecret, mlkemSharedSecret...)
 219  		ks.data = append(ks.data, mlkemKeyShare...)
 220  	}
 221  	ks.group = ke.id
 222  	return sharedKey, ks, nil
 223  }
 224  
 225  func (ke *hybridKeyExchange) clientSharedSecret(priv *keySharePrivateKeys, serverKeyShare []byte) ([]byte, error) {
 226  	if len(serverKeyShare) != ke.ecdhElementSize+ke.mlkemCiphertextSize {
 227  		return nil, errors.New("tls: invalid server key share length for hybrid key exchange")
 228  	}
 229  	var ecdhShareData, mlkemShareData []byte
 230  	if ke.id == X25519MLKEM768 {
 231  		mlkemShareData = serverKeyShare[:ke.mlkemCiphertextSize]
 232  		ecdhShareData = serverKeyShare[ke.mlkemCiphertextSize:]
 233  	} else {
 234  		ecdhShareData = serverKeyShare[:ke.ecdhElementSize]
 235  		mlkemShareData = serverKeyShare[ke.ecdhElementSize:]
 236  	}
 237  	ecdhSharedSecret, err := ke.ecdh.clientSharedSecret(priv, ecdhShareData)
 238  	if err != nil {
 239  		return nil, err
 240  	}
 241  	mlkemSharedSecret, err := priv.mlkem.Decapsulate(mlkemShareData)
 242  	if err != nil {
 243  		return nil, err
 244  	}
 245  	var sharedKey []byte
 246  	if ke.id == X25519MLKEM768 {
 247  		sharedKey = append(mlkemSharedSecret, ecdhSharedSecret...)
 248  	} else {
 249  		sharedKey = append(ecdhSharedSecret, mlkemSharedSecret...)
 250  	}
 251  	return sharedKey, nil
 252  }
 253