Source file src/crypto/internal/fips140/tls13/tls13.go

     1  // Copyright 2024 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 tls13 implements the TLS 1.3 Key Schedule as specified in RFC 8446,
     6  // Section 7.1 and allowed by FIPS 140-3 IG 2.4.B Resolution 7.
     7  package tls13
     8  
     9  import (
    10  	"crypto/internal/fips140"
    11  	"crypto/internal/fips140/hkdf"
    12  	"crypto/internal/fips140deps/byteorder"
    13  )
    14  
    15  // We don't set the service indicator in this package but we delegate that to
    16  // the underlying functions because the TLS 1.3 KDF does not have a standard of
    17  // its own.
    18  
    19  // ExpandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
    20  func ExpandLabel[H fips140.Hash](hash func() H, secret []byte, label string, context []byte, length int) []byte {
    21  	if len("tls13 ")+len(label) > 255 || len(context) > 255 {
    22  		// It should be impossible for this to panic: labels are fixed strings,
    23  		// and context is either a fixed-length computed hash, or parsed from a
    24  		// field which has the same length limitation.
    25  		//
    26  		// Another reasonable approach might be to return a randomized slice if
    27  		// we encounter an error, which would break the connection, but avoid
    28  		// panicking. This would perhaps be safer but significantly more
    29  		// confusing to users.
    30  		panic("tls13: label or context too long")
    31  	}
    32  	hkdfLabel := make([]byte, 0, 2+1+len("tls13 ")+len(label)+1+len(context))
    33  	hkdfLabel = byteorder.BEAppendUint16(hkdfLabel, uint16(length))
    34  	hkdfLabel = append(hkdfLabel, byte(len("tls13 ")+len(label)))
    35  	hkdfLabel = append(hkdfLabel, "tls13 "...)
    36  	hkdfLabel = append(hkdfLabel, label...)
    37  	hkdfLabel = append(hkdfLabel, byte(len(context)))
    38  	hkdfLabel = append(hkdfLabel, context...)
    39  	return hkdf.Expand(hash, secret, string(hkdfLabel), length)
    40  }
    41  
    42  func extract[H fips140.Hash](hash func() H, newSecret, currentSecret []byte) []byte {
    43  	if newSecret == nil {
    44  		newSecret = make([]byte, hash().Size())
    45  	}
    46  	return hkdf.Extract(hash, newSecret, currentSecret)
    47  }
    48  
    49  func deriveSecret[H fips140.Hash](hash func() H, secret []byte, label string, transcript fips140.Hash) []byte {
    50  	if transcript == nil {
    51  		transcript = hash()
    52  	}
    53  	return ExpandLabel(hash, secret, label, transcript.Sum(nil), transcript.Size())
    54  }
    55  
    56  const (
    57  	resumptionBinderLabel         = "res binder"
    58  	clientEarlyTrafficLabel       = "c e traffic"
    59  	clientHandshakeTrafficLabel   = "c hs traffic"
    60  	serverHandshakeTrafficLabel   = "s hs traffic"
    61  	clientApplicationTrafficLabel = "c ap traffic"
    62  	serverApplicationTrafficLabel = "s ap traffic"
    63  	earlyExporterLabel            = "e exp master"
    64  	exporterLabel                 = "exp master"
    65  	resumptionLabel               = "res master"
    66  )
    67  
    68  type EarlySecret struct {
    69  	secret []byte
    70  	hash   func() fips140.Hash
    71  }
    72  
    73  func NewEarlySecret[H fips140.Hash](hash func() H, psk []byte) *EarlySecret {
    74  	return &EarlySecret{
    75  		secret: extract(hash, psk, nil),
    76  		hash:   func() fips140.Hash { return hash() },
    77  	}
    78  }
    79  
    80  func (s *EarlySecret) ResumptionBinderKey() []byte {
    81  	return deriveSecret(s.hash, s.secret, resumptionBinderLabel, nil)
    82  }
    83  
    84  // ClientEarlyTrafficSecret derives the client_early_traffic_secret from the
    85  // early secret and the transcript up to the ClientHello.
    86  func (s *EarlySecret) ClientEarlyTrafficSecret(transcript fips140.Hash) []byte {
    87  	return deriveSecret(s.hash, s.secret, clientEarlyTrafficLabel, transcript)
    88  }
    89  
    90  type HandshakeSecret struct {
    91  	secret []byte
    92  	hash   func() fips140.Hash
    93  }
    94  
    95  func (s *EarlySecret) HandshakeSecret(sharedSecret []byte) *HandshakeSecret {
    96  	derived := deriveSecret(s.hash, s.secret, "derived", nil)
    97  	return &HandshakeSecret{
    98  		secret: extract(s.hash, sharedSecret, derived),
    99  		hash:   s.hash,
   100  	}
   101  }
   102  
   103  // ClientHandshakeTrafficSecret derives the client_handshake_traffic_secret from
   104  // the handshake secret and the transcript up to the ServerHello.
   105  func (s *HandshakeSecret) ClientHandshakeTrafficSecret(transcript fips140.Hash) []byte {
   106  	return deriveSecret(s.hash, s.secret, clientHandshakeTrafficLabel, transcript)
   107  }
   108  
   109  // ServerHandshakeTrafficSecret derives the server_handshake_traffic_secret from
   110  // the handshake secret and the transcript up to the ServerHello.
   111  func (s *HandshakeSecret) ServerHandshakeTrafficSecret(transcript fips140.Hash) []byte {
   112  	return deriveSecret(s.hash, s.secret, serverHandshakeTrafficLabel, transcript)
   113  }
   114  
   115  type MasterSecret struct {
   116  	secret []byte
   117  	hash   func() fips140.Hash
   118  }
   119  
   120  func (s *HandshakeSecret) MasterSecret() *MasterSecret {
   121  	derived := deriveSecret(s.hash, s.secret, "derived", nil)
   122  	return &MasterSecret{
   123  		secret: extract(s.hash, nil, derived),
   124  		hash:   s.hash,
   125  	}
   126  }
   127  
   128  // ClientApplicationTrafficSecret derives the client_application_traffic_secret_0
   129  // from the master secret and the transcript up to the server Finished.
   130  func (s *MasterSecret) ClientApplicationTrafficSecret(transcript fips140.Hash) []byte {
   131  	return deriveSecret(s.hash, s.secret, clientApplicationTrafficLabel, transcript)
   132  }
   133  
   134  // ServerApplicationTrafficSecret derives the server_application_traffic_secret_0
   135  // from the master secret and the transcript up to the server Finished.
   136  func (s *MasterSecret) ServerApplicationTrafficSecret(transcript fips140.Hash) []byte {
   137  	return deriveSecret(s.hash, s.secret, serverApplicationTrafficLabel, transcript)
   138  }
   139  
   140  // ResumptionMasterSecret derives the resumption_master_secret from the master secret
   141  // and the transcript up to the client Finished.
   142  func (s *MasterSecret) ResumptionMasterSecret(transcript fips140.Hash) []byte {
   143  	return deriveSecret(s.hash, s.secret, resumptionLabel, transcript)
   144  }
   145  
   146  type ExporterMasterSecret struct {
   147  	secret []byte
   148  	hash   func() fips140.Hash
   149  }
   150  
   151  // ExporterMasterSecret derives the exporter_master_secret from the master secret
   152  // and the transcript up to the server Finished.
   153  func (s *MasterSecret) ExporterMasterSecret(transcript fips140.Hash) *ExporterMasterSecret {
   154  	return &ExporterMasterSecret{
   155  		secret: deriveSecret(s.hash, s.secret, exporterLabel, transcript),
   156  		hash:   s.hash,
   157  	}
   158  }
   159  
   160  // EarlyExporterMasterSecret derives the exporter_master_secret from the early secret
   161  // and the transcript up to the ClientHello.
   162  func (s *EarlySecret) EarlyExporterMasterSecret(transcript fips140.Hash) *ExporterMasterSecret {
   163  	return &ExporterMasterSecret{
   164  		secret: deriveSecret(s.hash, s.secret, earlyExporterLabel, transcript),
   165  		hash:   s.hash,
   166  	}
   167  }
   168  
   169  func (s *ExporterMasterSecret) Exporter(label string, context []byte, length int) []byte {
   170  	secret := deriveSecret(s.hash, s.secret, label, nil)
   171  	h := s.hash()
   172  	h.Write(context)
   173  	return ExpandLabel(s.hash, secret, "exporter", h.Sum(nil), length)
   174  }
   175  
   176  func TestingOnlyExporterSecret(s *ExporterMasterSecret) []byte {
   177  	return s.secret
   178  }
   179  

View as plain text