...

Source file src/crypto/tls/key_schedule.go

Documentation: crypto/tls

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

View as plain text