Source file src/crypto/tls/key_schedule.go

     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(string, []byte, int) ([]byte, error) {
    47  	expMasterSecret := s.ExporterMasterSecret(transcript)
    48  	return func(label string, 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 := make([]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  

View as plain text