]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/internal/fips/tls13: implement TLS 1.3 KDF
authorFilippo Valsorda <filippo@golang.org>
Sat, 9 Nov 2024 15:23:22 +0000 (16:23 +0100)
committerGopher Robot <gobot@golang.org>
Tue, 19 Nov 2024 17:45:20 +0000 (17:45 +0000)
The new implementation encodes the key schedule into the type system,
which is actually nicer than what we had before.

For #69536

Change-Id: Iddab62c2aae40bc2425a155443576bb9b7aafe03
Reviewed-on: https://go-review.googlesource.com/c/go/+/626836
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Commit-Queue: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
src/crypto/internal/fips/cast_external_test.go
src/crypto/internal/fips/tls13/cast.go [new file with mode: 0644]
src/crypto/internal/fips/tls13/tls13.go [new file with mode: 0644]
src/crypto/tls/handshake_client.go
src/crypto/tls/handshake_client_tls13.go
src/crypto/tls/handshake_server_tls13.go
src/crypto/tls/key_schedule.go
src/crypto/tls/key_schedule_test.go
src/go/build/deps_test.go

index 60859a50d928f15d956a697f81b8bd7abc225869..1e4465dcee99010d6fabc7595fdbd1d47d375928 100644 (file)
@@ -18,6 +18,7 @@ import (
        _ "crypto/internal/fips/sha256"
        _ "crypto/internal/fips/sha3"
        _ "crypto/internal/fips/sha512"
+       _ "crypto/internal/fips/tls13"
 )
 
 func TestCAST(t *testing.T) {
diff --git a/src/crypto/internal/fips/tls13/cast.go b/src/crypto/internal/fips/tls13/cast.go
new file mode 100644 (file)
index 0000000..54b4a70
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls13
+
+import (
+       "bytes"
+       "crypto/internal/fips"
+       "crypto/internal/fips/sha256"
+       "errors"
+)
+
+func init() {
+       fips.CAST("TLSv1.3-SHA2-256", func() error {
+               input := []byte{
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                       0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+               }
+               want := []byte{
+                       0x78, 0x20, 0x71, 0x75, 0x52, 0xfd, 0x47, 0x67,
+                       0xe1, 0x07, 0x5c, 0x83, 0x74, 0x2e, 0x49, 0x43,
+                       0xf7, 0xe3, 0x08, 0x6a, 0x2a, 0xcb, 0x96, 0xc7,
+                       0xa3, 0x1f, 0xe3, 0x23, 0x56, 0x6e, 0x14, 0x5b,
+               }
+               es := NewEarlySecret(sha256.New, nil)
+               hs := es.HandshakeSecret(nil)
+               ms := hs.MasterSecret()
+               transcript := sha256.New()
+               transcript.Write(input)
+               if got := ms.ResumptionMasterSecret(transcript); !bytes.Equal(got, want) {
+                       return errors.New("unexpected result")
+               }
+               return nil
+       })
+}
diff --git a/src/crypto/internal/fips/tls13/tls13.go b/src/crypto/internal/fips/tls13/tls13.go
new file mode 100644 (file)
index 0000000..2c77b88
--- /dev/null
@@ -0,0 +1,178 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tls13 implements the TLS 1.3 Key Schedule as specified in RFC 8446,
+// Section 7.1 and allowed by FIPS 140-3 IG 2.4.B Resolution 7.
+package tls13
+
+import (
+       "crypto/internal/fips"
+       "crypto/internal/fips/hkdf"
+       "internal/byteorder"
+)
+
+// We don't set the service indicator in this package but we delegate that to
+// the underlying functions because the TLS 1.3 KDF does not have a standard of
+// its own.
+
+// ExpandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
+func ExpandLabel[H fips.Hash](hash func() H, secret []byte, label string, context []byte, length int) []byte {
+       if len("tls13 ")+len(label) > 255 || len(context) > 255 {
+               // It should be impossible for this to panic: labels are fixed strings,
+               // and context is either a fixed-length computed hash, or parsed from a
+               // field which has the same length limitation.
+               //
+               // Another reasonable approach might be to return a randomized slice if
+               // we encounter an error, which would break the connection, but avoid
+               // panicking. This would perhaps be safer but significantly more
+               // confusing to users.
+               panic("tls13: label or context too long")
+       }
+       hkdfLabel := make([]byte, 0, 2+1+len("tls13 ")+len(label)+1+len(context))
+       hkdfLabel = byteorder.BeAppendUint16(hkdfLabel, uint16(length))
+       hkdfLabel = append(hkdfLabel, byte(len("tls13 ")+len(label)))
+       hkdfLabel = append(hkdfLabel, "tls13 "...)
+       hkdfLabel = append(hkdfLabel, label...)
+       hkdfLabel = append(hkdfLabel, byte(len(context)))
+       hkdfLabel = append(hkdfLabel, context...)
+       return hkdf.Expand(hash, secret, hkdfLabel, length)
+}
+
+func extract[H fips.Hash](hash func() H, newSecret, currentSecret []byte) []byte {
+       if newSecret == nil {
+               newSecret = make([]byte, hash().Size())
+       }
+       return hkdf.Extract(hash, newSecret, currentSecret)
+}
+
+func deriveSecret[H fips.Hash](hash func() H, secret []byte, label string, transcript fips.Hash) []byte {
+       if transcript == nil {
+               transcript = hash()
+       }
+       return ExpandLabel(hash, secret, label, transcript.Sum(nil), transcript.Size())
+}
+
+const (
+       resumptionBinderLabel         = "res binder"
+       clientEarlyTrafficLabel       = "c e traffic"
+       clientHandshakeTrafficLabel   = "c hs traffic"
+       serverHandshakeTrafficLabel   = "s hs traffic"
+       clientApplicationTrafficLabel = "c ap traffic"
+       serverApplicationTrafficLabel = "s ap traffic"
+       earlyExporterLabel            = "e exp master"
+       exporterLabel                 = "exp master"
+       resumptionLabel               = "res master"
+)
+
+type EarlySecret struct {
+       secret []byte
+       hash   func() fips.Hash
+}
+
+func NewEarlySecret[H fips.Hash](hash func() H, psk []byte) *EarlySecret {
+       return &EarlySecret{
+               secret: extract(hash, psk, nil),
+               hash:   func() fips.Hash { return hash() },
+       }
+}
+
+func (s *EarlySecret) ResumptionBinderKey() []byte {
+       return deriveSecret(s.hash, s.secret, resumptionBinderLabel, nil)
+}
+
+// ClientEarlyTrafficSecret derives the client_early_traffic_secret from the
+// early secret and the transcript up to the ClientHello.
+func (s *EarlySecret) ClientEarlyTrafficSecret(transcript fips.Hash) []byte {
+       return deriveSecret(s.hash, s.secret, clientEarlyTrafficLabel, transcript)
+}
+
+type HandshakeSecret struct {
+       secret []byte
+       hash   func() fips.Hash
+}
+
+func (s *EarlySecret) HandshakeSecret(sharedSecret []byte) *HandshakeSecret {
+       derived := deriveSecret(s.hash, s.secret, "derived", nil)
+       return &HandshakeSecret{
+               secret: extract(s.hash, sharedSecret, derived),
+               hash:   s.hash,
+       }
+}
+
+// ClientHandshakeTrafficSecret derives the client_handshake_traffic_secret from
+// the handshake secret and the transcript up to the ServerHello.
+func (s *HandshakeSecret) ClientHandshakeTrafficSecret(transcript fips.Hash) []byte {
+       return deriveSecret(s.hash, s.secret, clientHandshakeTrafficLabel, transcript)
+}
+
+// ServerHandshakeTrafficSecret derives the server_handshake_traffic_secret from
+// the handshake secret and the transcript up to the ServerHello.
+func (s *HandshakeSecret) ServerHandshakeTrafficSecret(transcript fips.Hash) []byte {
+       return deriveSecret(s.hash, s.secret, serverHandshakeTrafficLabel, transcript)
+}
+
+type MasterSecret struct {
+       secret []byte
+       hash   func() fips.Hash
+}
+
+func (s *HandshakeSecret) MasterSecret() *MasterSecret {
+       derived := deriveSecret(s.hash, s.secret, "derived", nil)
+       return &MasterSecret{
+               secret: extract(s.hash, nil, derived),
+               hash:   s.hash,
+       }
+}
+
+// ClientApplicationTrafficSecret derives the client_application_traffic_secret_0
+// from the master secret and the transcript up to the server Finished.
+func (s *MasterSecret) ClientApplicationTrafficSecret(transcript fips.Hash) []byte {
+       return deriveSecret(s.hash, s.secret, clientApplicationTrafficLabel, transcript)
+}
+
+// ServerApplicationTrafficSecret derives the server_application_traffic_secret_0
+// from the master secret and the transcript up to the server Finished.
+func (s *MasterSecret) ServerApplicationTrafficSecret(transcript fips.Hash) []byte {
+       return deriveSecret(s.hash, s.secret, serverApplicationTrafficLabel, transcript)
+}
+
+// ResumptionMasterSecret derives the resumption_master_secret from the master secret
+// and the transcript up to the client Finished.
+func (s *MasterSecret) ResumptionMasterSecret(transcript fips.Hash) []byte {
+       return deriveSecret(s.hash, s.secret, resumptionLabel, transcript)
+}
+
+type ExporterMasterSecret struct {
+       secret []byte
+       hash   func() fips.Hash
+}
+
+// ExporterMasterSecret derives the exporter_master_secret from the master secret
+// and the transcript up to the server Finished.
+func (s *MasterSecret) ExporterMasterSecret(transcript fips.Hash) *ExporterMasterSecret {
+       return &ExporterMasterSecret{
+               secret: deriveSecret(s.hash, s.secret, exporterLabel, transcript),
+               hash:   s.hash,
+       }
+}
+
+// EarlyExporterMasterSecret derives the exporter_master_secret from the early secret
+// and the transcript up to the ClientHello.
+func (s *EarlySecret) EarlyExporterMasterSecret(transcript fips.Hash) *ExporterMasterSecret {
+       return &ExporterMasterSecret{
+               secret: deriveSecret(s.hash, s.secret, earlyExporterLabel, transcript),
+               hash:   s.hash,
+       }
+}
+
+func (s *ExporterMasterSecret) Exporter(label string, context []byte, length int) []byte {
+       secret := deriveSecret(s.hash, s.secret, label, nil)
+       h := s.hash()
+       h.Write(context)
+       return ExpandLabel(s.hash, secret, "exporter", h.Sum(nil), length)
+}
+
+func TestingOnlyExporterSecret(s *ExporterMasterSecret) []byte {
+       return s.secret
+}
index 760e827f467f153254bee3513e18fb0da1123a0b..f6bccc40bcb022018758960144d23de76a269b2a 100644 (file)
@@ -10,6 +10,7 @@ import (
        "crypto"
        "crypto/ecdsa"
        "crypto/ed25519"
+       "crypto/internal/fips/tls13"
        "crypto/internal/hpke"
        "crypto/internal/mlkem768"
        "crypto/rsa"
@@ -324,7 +325,7 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
                if err := transcriptMsg(hello, transcript); err != nil {
                        return err
                }
-               earlyTrafficSecret := suite.deriveSecret(earlySecret, clientEarlyTrafficLabel, transcript)
+               earlyTrafficSecret := earlySecret.ClientEarlyTrafficSecret(transcript)
                c.quicSetWriteSecret(QUICEncryptionLevelEarly, suite.id, earlyTrafficSecret)
        }
 
@@ -382,7 +383,7 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
 }
 
 func (c *Conn) loadSession(hello *clientHelloMsg) (
-       session *SessionState, earlySecret, binderKey []byte, err error) {
+       session *SessionState, earlySecret *tls13.EarlySecret, binderKey []byte, err error) {
        if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
                return nil, nil, nil, nil
        }
@@ -509,8 +510,8 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (
        hello.pskBinders = [][]byte{make([]byte, cipherSuite.hash.Size())}
 
        // Compute the PSK binders. See RFC 8446, Section 4.2.11.2.
-       earlySecret = cipherSuite.extract(session.secret, nil)
-       binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil)
+       earlySecret = tls13.NewEarlySecret(cipherSuite.hash.New, session.secret)
+       binderKey = earlySecret.ResumptionBinderKey()
        transcript := cipherSuite.hash.New()
        if err := computeAndUpdatePSK(hello, binderKey, transcript, cipherSuite.finishedHash); err != nil {
                return nil, nil, nil, err
index 21a501fbfd592be4b0c7130c6053b606dfe48944..cdef806ab050c0bc454d60cbc477814bbc3eb974 100644 (file)
@@ -9,6 +9,8 @@ import (
        "context"
        "crypto"
        "crypto/hmac"
+       "crypto/internal/fips/hkdf"
+       "crypto/internal/fips/tls13"
        "crypto/internal/mlkem768"
        "crypto/rsa"
        "crypto/subtle"
@@ -26,7 +28,7 @@ type clientHandshakeStateTLS13 struct {
        keyShareKeys *keySharePrivateKeys
 
        session     *SessionState
-       earlySecret []byte
+       earlySecret *tls13.EarlySecret
        binderKey   []byte
 
        certReq       *certificateRequestMsgTLS13
@@ -34,7 +36,7 @@ type clientHandshakeStateTLS13 struct {
        sentDummyCCS  bool
        suite         *cipherSuiteTLS13
        transcript    hash.Hash
-       masterSecret  []byte
+       masterSecret  *tls13.MasterSecret
        trafficSecret []byte // client_application_traffic_secret_0
 
        echContext *echContext
@@ -89,8 +91,8 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
                confTranscript.Write(hs.serverHello.original[:30])
                confTranscript.Write(make([]byte, 8))
                confTranscript.Write(hs.serverHello.original[38:])
-               acceptConfirmation := hs.suite.expandLabel(
-                       hs.suite.extract(hs.echContext.innerHello.random, nil),
+               acceptConfirmation := tls13.ExpandLabel(hs.suite.hash.New,
+                       hkdf.Extract(hs.suite.hash.New, hs.echContext.innerHello.random, nil),
                        "ech accept confirmation",
                        confTranscript.Sum(nil),
                        8,
@@ -266,8 +268,8 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
                        copy(hrrHello, hs.serverHello.original)
                        hrrHello = bytes.Replace(hrrHello, hs.serverHello.encryptedClientHello, make([]byte, 8), 1)
                        confTranscript.Write(hrrHello)
-                       acceptConfirmation := hs.suite.expandLabel(
-                               hs.suite.extract(hs.echContext.innerHello.random, nil),
+                       acceptConfirmation := tls13.ExpandLabel(hs.suite.hash.New,
+                               hkdf.Extract(hs.suite.hash.New, hs.echContext.innerHello.random, nil),
                                "hrr ech accept confirmation",
                                confTranscript.Sum(nil),
                                8,
@@ -511,17 +513,14 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
 
        earlySecret := hs.earlySecret
        if !hs.usingPSK {
-               earlySecret = hs.suite.extract(nil, nil)
+               earlySecret = tls13.NewEarlySecret(hs.suite.hash.New, nil)
        }
 
-       handshakeSecret := hs.suite.extract(sharedKey,
-               hs.suite.deriveSecret(earlySecret, "derived", nil))
+       handshakeSecret := earlySecret.HandshakeSecret(sharedKey)
 
-       clientSecret := hs.suite.deriveSecret(handshakeSecret,
-               clientHandshakeTrafficLabel, hs.transcript)
+       clientSecret := handshakeSecret.ClientHandshakeTrafficSecret(hs.transcript)
        c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
-       serverSecret := hs.suite.deriveSecret(handshakeSecret,
-               serverHandshakeTrafficLabel, hs.transcript)
+       serverSecret := handshakeSecret.ServerHandshakeTrafficSecret(hs.transcript)
        c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
 
        if c.quic != nil {
@@ -543,8 +542,7 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
                return err
        }
 
-       hs.masterSecret = hs.suite.extract(nil,
-               hs.suite.deriveSecret(handshakeSecret, "derived", nil))
+       hs.masterSecret = handshakeSecret.MasterSecret()
 
        return nil
 }
@@ -732,10 +730,8 @@ func (hs *clientHandshakeStateTLS13) readServerFinished() error {
 
        // Derive secrets that take context through the server Finished.
 
-       hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret,
-               clientApplicationTrafficLabel, hs.transcript)
-       serverSecret := hs.suite.deriveSecret(hs.masterSecret,
-               serverApplicationTrafficLabel, hs.transcript)
+       hs.trafficSecret = hs.masterSecret.ClientApplicationTrafficSecret(hs.transcript)
+       serverSecret := hs.masterSecret.ServerApplicationTrafficSecret(hs.transcript)
        c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
 
        err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret)
@@ -842,8 +838,7 @@ func (hs *clientHandshakeStateTLS13) sendClientFinished() error {
        c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret)
 
        if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil {
-               c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
-                       resumptionLabel, hs.transcript)
+               c.resumptionSecret = hs.masterSecret.ResumptionMasterSecret(hs.transcript)
        }
 
        if c.quic != nil {
@@ -887,7 +882,7 @@ func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
                return c.sendAlert(alertInternalError)
        }
 
-       psk := cipherSuite.expandLabel(c.resumptionSecret, "resumption",
+       psk := tls13.ExpandLabel(cipherSuite.hash.New, c.resumptionSecret, "resumption",
                msg.nonce, cipherSuite.hash.Size())
 
        session := c.sessionState()
index b8cf4c3fa50b242e70fb635a156bff83979b9853..29add50d6ea33772c4d55dc663670b0d02611ea5 100644 (file)
@@ -9,6 +9,7 @@ import (
        "context"
        "crypto"
        "crypto/hmac"
+       "crypto/internal/fips/tls13"
        "crypto/internal/mlkem768"
        "crypto/rsa"
        "errors"
@@ -35,10 +36,10 @@ type serverHandshakeStateTLS13 struct {
        suite           *cipherSuiteTLS13
        cert            *Certificate
        sigAlg          SignatureScheme
-       earlySecret     []byte
+       earlySecret     *tls13.EarlySecret
        sharedKey       []byte
-       handshakeSecret []byte
-       masterSecret    []byte
+       handshakeSecret *tls13.HandshakeSecret
+       masterSecret    *tls13.MasterSecret
        trafficSecret   []byte // client_application_traffic_secret_0
        transcript      hash.Hash
        clientFinished  []byte
@@ -382,8 +383,8 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
                        }
                }
 
-               hs.earlySecret = hs.suite.extract(sessionState.secret, nil)
-               binderKey := hs.suite.deriveSecret(hs.earlySecret, resumptionBinderLabel, nil)
+               hs.earlySecret = tls13.NewEarlySecret(hs.suite.hash.New, sessionState.secret)
+               binderKey := hs.earlySecret.ResumptionBinderKey()
                // Clone the transcript in case a HelloRetryRequest was recorded.
                transcript := cloneHash(hs.transcript, hs.suite.hash)
                if transcript == nil {
@@ -411,7 +412,7 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
                        if err := transcriptMsg(hs.clientHello, transcript); err != nil {
                                return err
                        }
-                       earlyTrafficSecret := hs.suite.deriveSecret(hs.earlySecret, clientEarlyTrafficLabel, transcript)
+                       earlyTrafficSecret := hs.earlySecret.ClientEarlyTrafficSecret(transcript)
                        c.quicSetReadSecret(QUICEncryptionLevelEarly, hs.suite.id, earlyTrafficSecret)
                }
 
@@ -649,16 +650,13 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
 
        earlySecret := hs.earlySecret
        if earlySecret == nil {
-               earlySecret = hs.suite.extract(nil, nil)
+               earlySecret = tls13.NewEarlySecret(hs.suite.hash.New, nil)
        }
-       hs.handshakeSecret = hs.suite.extract(hs.sharedKey,
-               hs.suite.deriveSecret(earlySecret, "derived", nil))
+       hs.handshakeSecret = earlySecret.HandshakeSecret(hs.sharedKey)
 
-       clientSecret := hs.suite.deriveSecret(hs.handshakeSecret,
-               clientHandshakeTrafficLabel, hs.transcript)
+       clientSecret := hs.handshakeSecret.ClientHandshakeTrafficSecret(hs.transcript)
        c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
-       serverSecret := hs.suite.deriveSecret(hs.handshakeSecret,
-               serverHandshakeTrafficLabel, hs.transcript)
+       serverSecret := hs.handshakeSecret.ServerHandshakeTrafficSecret(hs.transcript)
        c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
 
        if c.quic != nil {
@@ -783,13 +781,10 @@ func (hs *serverHandshakeStateTLS13) sendServerFinished() error {
 
        // Derive secrets that take context through the server Finished.
 
-       hs.masterSecret = hs.suite.extract(nil,
-               hs.suite.deriveSecret(hs.handshakeSecret, "derived", nil))
+       hs.masterSecret = hs.handshakeSecret.MasterSecret()
 
-       hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret,
-               clientApplicationTrafficLabel, hs.transcript)
-       serverSecret := hs.suite.deriveSecret(hs.masterSecret,
-               serverApplicationTrafficLabel, hs.transcript)
+       hs.trafficSecret = hs.masterSecret.ClientApplicationTrafficSecret(hs.transcript)
+       serverSecret := hs.masterSecret.ServerApplicationTrafficSecret(hs.transcript)
        c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
 
        if c.quic != nil {
@@ -855,8 +850,7 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
                return err
        }
 
-       c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
-               resumptionLabel, hs.transcript)
+       c.resumptionSecret = hs.masterSecret.ResumptionMasterSecret(hs.transcript)
 
        if !hs.shouldSendSessionTickets() {
                return nil
@@ -871,7 +865,7 @@ func (c *Conn) sendSessionTicket(earlyData bool, extra [][]byte) error {
        }
        // ticket_nonce, which must be unique per connection, is always left at
        // zero because we only ever send one ticket per connection.
-       psk := suite.expandLabel(c.resumptionSecret, "resumption",
+       psk := tls13.ExpandLabel(suite.hash.New, c.resumptionSecret, "resumption",
                nil, suite.hash.Size())
 
        m := new(newSessionTicketMsgTLS13)
index 1636baf79e72885a4df338af5fef5b884e8d64b3..9c76ebe36702a770fed972303604822e24adaab8 100644 (file)
@@ -7,93 +7,28 @@ package tls
 import (
        "crypto/ecdh"
        "crypto/hmac"
+       "crypto/internal/fips/tls13"
        "crypto/internal/mlkem768"
        "errors"
-       "fmt"
        "hash"
        "io"
 
-       "golang.org/x/crypto/cryptobyte"
-       "golang.org/x/crypto/hkdf"
        "golang.org/x/crypto/sha3"
 )
 
 // This file contains the functions necessary to compute the TLS 1.3 key
 // schedule. See RFC 8446, Section 7.
 
-const (
-       resumptionBinderLabel         = "res binder"
-       clientEarlyTrafficLabel       = "c e traffic"
-       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"
-)
-
-// expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
-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)
-       })
-       hkdfLabelBytes, err := hkdfLabel.Bytes()
-       if err != nil {
-               // Rather than calling BytesOrPanic, we explicitly handle this error, in
-               // order to provide a reasonable error message. It should be basically
-               // impossible for this to panic, and routing errors back through the
-               // tree rooted in this function is quite painful. The labels are fixed
-               // size, and the context is either a fixed-length computed hash, or
-               // parsed from a field which has the same length limitation. As such, an
-               // error here is likely to only be caused during development.
-               //
-               // NOTE: another reasonable approach here might be to return a
-               // randomized slice if we encounter an error, which would break the
-               // connection, but avoid panicking. This would perhaps be safer but
-               // significantly more confusing to users.
-               panic(fmt.Errorf("failed to construct HKDF label: %s", err))
-       }
-       out := make([]byte, length)
-       n, err := hkdf.Expand(c.hash.New, secret, hkdfLabelBytes).Read(out)
-       if err != nil || n != length {
-               panic("tls: HKDF-Expand-Label invocation failed unexpectedly")
-       }
-       return out
-}
-
-// deriveSecret implements Derive-Secret from RFC 8446, Section 7.1.
-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())
-}
-
-// extract implements HKDF-Extract with the cipher suite hash.
-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)
-}
-
 // nextTrafficSecret generates the next traffic secret, given the current one,
 // according to RFC 8446, Section 7.2.
 func (c *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte {
-       return c.expandLabel(trafficSecret, trafficUpdateLabel, nil, c.hash.Size())
+       return tls13.ExpandLabel(c.hash.New, trafficSecret, "traffic upd", nil, c.hash.Size())
 }
 
 // trafficKey generates traffic keys according to RFC 8446, Section 7.3.
 func (c *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) {
-       key = c.expandLabel(trafficSecret, "key", nil, c.keyLen)
-       iv = c.expandLabel(trafficSecret, "iv", nil, aeadNonceLength)
+       key = tls13.ExpandLabel(c.hash.New, trafficSecret, "key", nil, c.keyLen)
+       iv = tls13.ExpandLabel(c.hash.New, trafficSecret, "iv", nil, aeadNonceLength)
        return
 }
 
@@ -101,7 +36,7 @@ func (c *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) {
 // to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey
 // selection.
 func (c *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte {
-       finishedKey := c.expandLabel(baseKey, "finished", nil, c.hash.Size())
+       finishedKey := tls13.ExpandLabel(c.hash.New, baseKey, "finished", nil, c.hash.Size())
        verifyData := hmac.New(c.hash.New, finishedKey)
        verifyData.Write(transcript.Sum(nil))
        return verifyData.Sum(nil)
@@ -109,13 +44,10 @@ func (c *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []
 
 // exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to
 // RFC 8446, Section 7.5.
-func (c *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript hash.Hash) func(string, []byte, int) ([]byte, error) {
-       expMasterSecret := c.deriveSecret(masterSecret, exporterLabel, transcript)
+func (c *cipherSuiteTLS13) exportKeyingMaterial(s *tls13.MasterSecret, transcript hash.Hash) func(string, []byte, int) ([]byte, error) {
+       expMasterSecret := s.ExporterMasterSecret(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
+               return expMasterSecret.Exporter(label, context, length), nil
        }
 }
 
index 3ffdf6c109ef843ecc233d76f39d796e6e078941..02187e7e5f18cd44f71c75a3e634840c7c06993c 100644 (file)
@@ -6,14 +6,81 @@ package tls
 
 import (
        "bytes"
+       "crypto/internal/fips/tls13"
        "crypto/internal/mlkem768"
+       "crypto/sha256"
        "encoding/hex"
-       "hash"
        "strings"
        "testing"
        "unicode"
 )
 
+func TestACVPVectors(t *testing.T) {
+       // https://github.com/usnistgov/ACVP-Server/blob/3a7333f63/gen-val/json-files/TLS-v1.3-KDF-RFC8446/prompt.json#L428-L436
+       psk := fromHex("56288B726C73829F7A3E47B103837C8139ACF552E7530C7A710B35ED41191698")
+       dhe := fromHex("EFFE9EC26AA29FD750DFA6A10B944D74071595B27EE88887D5E11C84590B5CC3")
+       helloClientRandom := fromHex("E9137679E582BA7C1DB41CF725F86C6D09C8C05F297BAD9A65B552EAF524FDE4")
+       helloServerRandom := fromHex("23ECCFD030790748C8F8D8A656FD98D717F1B62AF3712F97211D2070B499F98A")
+       finishedClientRandom := fromHex("62A62FA75563ED4FDCAA0BC16567B314871C304ACF06B0FFC3F08C1797594D43")
+       finishedServerRandom := fromHex("C750EDA6696CD101B142BD79E00E6AC8C5F2C0ABC78DD64F4D991326659E9299")
+
+       // https://github.com/usnistgov/ACVP-Server/blob/3a7333f63/gen-val/json-files/TLS-v1.3-KDF-RFC8446/expectedResults.json#L571-L581
+       clientEarlyTrafficSecret := fromHex("3272189698C3594D18F58EFA3F12B638A249515099BE7A2FA9836BABE74F0111")
+       earlyExporterMasterSecret := fromHex("88E078F562CDC930219F6A5E98A1CE8C6E5F3DAC5AC516459A96F2EF8F114C66")
+       clientHandshakeTrafficSecret := fromHex("B32306C3CE9932C460A1FE6C0F060593974842036B96FA45049B7352E71C2AD2")
+       serverHandshakeTrafficSecret := fromHex("22787F8CA269D34BC549AC8BA19F2040938A3AA370D7CC9D60F720882B88D01B")
+       clientApplicationTrafficSecret := fromHex("47D7EA08397B5871154B0FE85584BCC30A87C69E84D69B56007C5B21F76493BA")
+       serverApplicationTrafficSecret := fromHex("EFBDB0C873C0480DA57307083839A8984BE25B9A8545E4FCA029940FE2800565")
+       exporterMasterSecret := fromHex("8A43D787EE3804EAD4A2A5B32972F9896B696295645D7222E1FD081DDD939834")
+       resumptionMasterSecret := fromHex("5F4C961329C91044011ACBECB0B289282E0E3FED045CB3EA924DFFE5FE654B3D")
+
+       // The "Random" values are undocumented, but they are meant to be written to
+       // the hash in sequence to develop the transcript.
+       transcript := sha256.New()
+
+       es := tls13.NewEarlySecret(sha256.New, psk)
+
+       transcript.Write(helloClientRandom)
+
+       if got := es.ClientEarlyTrafficSecret(transcript); !bytes.Equal(got, clientEarlyTrafficSecret) {
+               t.Errorf("clientEarlyTrafficSecret = %x, want %x", got, clientEarlyTrafficSecret)
+       }
+       if got := tls13.TestingOnlyExporterSecret(es.EarlyExporterMasterSecret(transcript)); !bytes.Equal(got, earlyExporterMasterSecret) {
+               t.Errorf("earlyExporterMasterSecret = %x, want %x", got, earlyExporterMasterSecret)
+       }
+
+       hs := es.HandshakeSecret(dhe)
+
+       transcript.Write(helloServerRandom)
+
+       if got := hs.ClientHandshakeTrafficSecret(transcript); !bytes.Equal(got, clientHandshakeTrafficSecret) {
+               t.Errorf("clientHandshakeTrafficSecret = %x, want %x", got, clientHandshakeTrafficSecret)
+       }
+       if got := hs.ServerHandshakeTrafficSecret(transcript); !bytes.Equal(got, serverHandshakeTrafficSecret) {
+               t.Errorf("serverHandshakeTrafficSecret = %x, want %x", got, serverHandshakeTrafficSecret)
+       }
+
+       ms := hs.MasterSecret()
+
+       transcript.Write(finishedServerRandom)
+
+       if got := ms.ClientApplicationTrafficSecret(transcript); !bytes.Equal(got, clientApplicationTrafficSecret) {
+               t.Errorf("clientApplicationTrafficSecret = %x, want %x", got, clientApplicationTrafficSecret)
+       }
+       if got := ms.ServerApplicationTrafficSecret(transcript); !bytes.Equal(got, serverApplicationTrafficSecret) {
+               t.Errorf("serverApplicationTrafficSecret = %x, want %x", got, serverApplicationTrafficSecret)
+       }
+       if got := tls13.TestingOnlyExporterSecret(ms.ExporterMasterSecret(transcript)); !bytes.Equal(got, exporterMasterSecret) {
+               t.Errorf("exporterMasterSecret = %x, want %x", got, exporterMasterSecret)
+       }
+
+       transcript.Write(finishedClientRandom)
+
+       if got := ms.ResumptionMasterSecret(transcript); !bytes.Equal(got, resumptionMasterSecret) {
+               t.Errorf("resumptionMasterSecret = %x, want %x", got, resumptionMasterSecret)
+       }
+}
+
 // This file contains tests derived from draft-ietf-tls-tls13-vectors-07.
 
 func parseVector(v string) []byte {
@@ -32,78 +99,6 @@ func parseVector(v string) []byte {
        return res
 }
 
-func TestDeriveSecret(t *testing.T) {
-       chTranscript := cipherSuitesTLS13[0].hash.New()
-       chTranscript.Write(parseVector(`
-       payload (512 octets):  01 00 01 fc 03 03 1b c3 ce b6 bb e3 9c ff
-       93 83 55 b5 a5 0a db 6d b2 1b 7a 6a f6 49 d7 b4 bc 41 9d 78 76
-       48 7d 95 00 00 06 13 01 13 03 13 02 01 00 01 cd 00 00 00 0b 00
-       09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 12
-       00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 33 00
-       26 00 24 00 1d 00 20 e4 ff b6 8a c0 5f 8d 96 c9 9d a2 66 98 34
-       6c 6b e1 64 82 ba dd da fe 05 1a 66 b4 f1 8d 66 8f 0b 00 2a 00
-       00 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 02
-       03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 02
-       02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 00 15 00 57 00 00 00
-       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-       00 29 00 dd 00 b8 00 b2 2c 03 5d 82 93 59 ee 5f f7 af 4e c9 00
-       00 00 00 26 2a 64 94 dc 48 6d 2c 8a 34 cb 33 fa 90 bf 1b 00 70
-       ad 3c 49 88 83 c9 36 7c 09 a2 be 78 5a bc 55 cd 22 60 97 a3 a9
-       82 11 72 83 f8 2a 03 a1 43 ef d3 ff 5d d3 6d 64 e8 61 be 7f d6
-       1d 28 27 db 27 9c ce 14 50 77 d4 54 a3 66 4d 4e 6d a4 d2 9e e0
-       37 25 a6 a4 da fc d0 fc 67 d2 ae a7 05 29 51 3e 3d a2 67 7f a5
-       90 6c 5b 3f 7d 8f 92 f2 28 bd a4 0d da 72 14 70 f9 fb f2 97 b5
-       ae a6 17 64 6f ac 5c 03 27 2e 97 07 27 c6 21 a7 91 41 ef 5f 7d
-       e6 50 5e 5b fb c3 88 e9 33 43 69 40 93 93 4a e4 d3 57 fa d6 aa
-       cb 00 21 20 3a dd 4f b2 d8 fd f8 22 a0 ca 3c f7 67 8e f5 e8 8d
-       ae 99 01 41 c5 92 4d 57 bb 6f a3 1b 9e 5f 9d`))
-
-       type args struct {
-               secret     []byte
-               label      string
-               transcript hash.Hash
-       }
-       tests := []struct {
-               name string
-               args args
-               want []byte
-       }{
-               {
-                       `derive secret for handshake "tls13 derived"`,
-                       args{
-                               parseVector(`PRK (32 octets):  33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2
-                               10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a`),
-                               "derived",
-                               nil,
-                       },
-                       parseVector(`expanded (32 octets):  6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba
-                       b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba`),
-               },
-               {
-                       `derive secret "tls13 c e traffic"`,
-                       args{
-                               parseVector(`PRK (32 octets):  9b 21 88 e9 b2 fc 6d 64 d7 1d c3 29 90 0e 20 bb
-                               41 91 50 00 f6 78 aa 83 9c bb 79 7c b7 d8 33 2c`),
-                               "c e traffic",
-                               chTranscript,
-                       },
-                       parseVector(`expanded (32 octets):  3f bb e6 a6 0d eb 66 c3 0a 32 79 5a ba 0e
-                       ff 7e aa 10 10 55 86 e7 be 5c 09 67 8d 63 b6 ca ab 62`),
-               },
-       }
-       for _, tt := range tests {
-               t.Run(tt.name, func(t *testing.T) {
-                       c := cipherSuitesTLS13[0]
-                       if got := c.deriveSecret(tt.args.secret, tt.args.label, tt.args.transcript); !bytes.Equal(got, tt.want) {
-                               t.Errorf("cipherSuiteTLS13.deriveSecret() = % x, want % x", got, tt.want)
-                       }
-               })
-       }
-}
-
 func TestTrafficKey(t *testing.T) {
        trafficSecret := parseVector(
                `PRK (32 octets):  b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4
@@ -124,57 +119,6 @@ func TestTrafficKey(t *testing.T) {
        }
 }
 
-func TestExtract(t *testing.T) {
-       type args struct {
-               newSecret     []byte
-               currentSecret []byte
-       }
-       tests := []struct {
-               name string
-               args args
-               want []byte
-       }{
-               {
-                       `extract secret "early"`,
-                       args{
-                               nil,
-                               nil,
-                       },
-                       parseVector(`secret (32 octets):  33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c
-                       e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a`),
-               },
-               {
-                       `extract secret "master"`,
-                       args{
-                               nil,
-                               parseVector(`salt (32 octets):  43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 90 b5
-                               31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4`),
-                       },
-                       parseVector(`secret (32 octets):  18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a
-                       47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19`),
-               },
-               {
-                       `extract secret "handshake"`,
-                       args{
-                               parseVector(`IKM (32 octets):  8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d
-                               35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d`),
-                               parseVector(`salt (32 octets):  6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba b6 97
-                               16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba`),
-                       },
-                       parseVector(`secret (32 octets):  1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b
-                       01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac`),
-               },
-       }
-       for _, tt := range tests {
-               t.Run(tt.name, func(t *testing.T) {
-                       c := cipherSuitesTLS13[0]
-                       if got := c.extract(tt.args.newSecret, tt.args.currentSecret); !bytes.Equal(got, tt.want) {
-                               t.Errorf("cipherSuiteTLS13.extract() = % x, want % x", got, tt.want)
-                       }
-               })
-       }
-}
-
 func TestKyberDecapsulate(t *testing.T) {
        // From https://pq-crystals.org/kyber/data/kyber-submission-nist-round3.zip
        dkBytes, _ := hex.DecodeString("07638FB69868F3D320E5862BD96933FEB311B362093C9B5D50170BCED43F1B536D9A204BB1F22695950BA1F2A9E8EB828B284488760B3FC84FABA04275D5628E39C5B2471374283C503299C0AB49B66B8BBB56A4186624F919A2BA59BB08D8551880C2BEFC4F87F25F59AB587A79C327D792D54C974A69262FF8A78938289E9A87B688B083E0595FE218B6BB1505941CE2E81A5A64C5AAC60417256985349EE47A52420A5F97477B7236AC76BC70E8288729287EE3E34A3DBC3683C0B7B10029FC203418537E7466BA6385A8FF301EE12708F82AAA1E380FC7A88F8F205AB7E88D7E95952A55BA20D09B79A47141D62BF6EB7DD307B08ECA13A5BC5F6B68581C6865B27BBCDDAB142F4B2CBFF488C8A22705FAA98A2B9EEA3530C76662335CC7EA3A00777725EBCCCD2A4636B2D9122FF3AB77123CE0883C1911115E50C9E8A94194E48DD0D09CFFB3ADCD2C1E92430903D07ADBF00532031575AA7F9E7B5A1F3362DEC936D4043C05F2476C07578BC9CBAF2AB4E382727AD41686A96B2548820BB03B32F11B2811AD62F489E951632ABA0D1DF89680CC8A8B53B481D92A68D70B4EA1C3A6A561C0692882B5CA8CC942A8D495AFCB06DE89498FB935B775908FE7A03E324D54CC19D4E1AABD3593B38B19EE1388FE492B43127E5A504253786A0D69AD32601C28E2C88504A5BA599706023A61363E17C6B9BB59BDC697452CD059451983D738CA3FD034E3F5988854CA05031DB09611498988197C6B30D258DFE26265541C89A4B31D6864E9389B03CB74F7EC4323FB9421A4B9790A26D17B0398A26767350909F84D57B6694DF830664CA8B3C3C03ED2AE67B89006868A68527CCD666459AB7F056671000C6164D3A7F266A14D97CBD7004D6C92CACA770B844A4FA9B182E7B18CA885082AC5646FCB4A14E1685FEB0C9CE3372AB95365C04FD83084F80A23FF10A05BF15F7FA5ACC6C0CB462C33CA524FA6B8BB359043BA68609EAA2536E81D08463B19653B5435BA946C9ADDEB202B04B031CC960DCC12E4518D428B32B257A4FC7313D3A7980D80082E934F9D95C32B0A0191A23604384DD9E079BBBAA266D14C3F756B9F2133107433A4E83FA7187282A809203A4FAF841851833D121AC383843A5E55BC2381425E16C7DB4CC9AB5C1B0D91A47E2B8DE0E582C86B6B0D907BB360B97F40AB5D038F6B75C814B27D9B968D419832BC8C2BEE605EF6E5059D33100D90485D378450014221736C07407CAC260408AA64926619788B8601C2A752D1A6CBF820D7C7A04716203225B3895B9342D147A8185CFC1BB65BA06B4142339903C0AC4651385B45D98A8B19D28CD6BAB088787F7EE1B12461766B43CBCCB96434427D93C065550688F6948ED1B5475A425F1B85209D061C08B56C1CC069F6C0A7C6F29358CAB911087732A649D27C9B98F9A48879387D9B00C25959A71654D6F6A946164513E47A75D005986C2363C09F6B537ECA78B9303A5FA457608A586A653A347DB04DFCC19175B3A301172536062A658A95277570C8852CA8973F4AE123A334047DD711C8927A634A03388A527B034BF7A8170FA702C1F7C23EC32D18A2374890BE9C787A9409C82D192C4BB705A2F996CE405DA72C2D9C843EE9F8313ECC7F86D6294D59159D9A879A542E260922ADF999051CC45200C9FFDB60449C49465979272367C083A7D6267A3ED7A7FD47957C219327F7CA73A4007E1627F00B11CC80573C15AEE6640FB8562DFA6B240CA0AD351AC4AC155B96C14C8AB13DD262CDFD51C4BB5572FD616553D17BDD430ACBEA3E95F0B698D66990AB51E5D03783A8B3D278A5720454CF9695CFDCA08485BA099C51CD92A7EA7587C1D15C28E609A81852601B0604010679AA482D51261EC36E36B8719676217FD74C54786488F4B4969C05A8BA27CA3A77CCE73B965923CA554E422B9B61F4754641608AC16C9B8587A32C1C5DD788F88B36B717A46965635DEB67F45B129B99070909C93EB80B42C2B3F3F70343A7CF37E8520E7BCFC416ACA4F18C7981262BA2BFC756AE03278F0EC66DC2057696824BA6769865A601D7148EF6F54E5AF5686AA2906F994CE38A5E0B938F239007003022C03392DF3401B1E4A3A7EBC6161449F73374C8B0140369343D9295FDF511845C4A46EBAAB6CA5492F6800B98C0CC803653A4B1D6E6AAED1932BACC5FEFAA818BA502859BA5494C5F5402C8536A9C4C1888150617F80098F6B2A99C39BC5DC7CF3B5900A21329AB59053ABAA64ED163E859A8B3B3CA3359B750CCC3E710C7AC43C8191CB5D68870C06391C0CB8AEC72B897AC6BE7FBAACC676ED66314C83630E89448C88A1DF04ACEB23ABF2E409EF333C622289C18A2134E650C45257E47475FA33AA537A5A8F7680214716C50D470E3284963CA64F54677AEC54B5272162BF52BC8142E1D4183FC017454A6B5A496831759064024745978CBD51A6CEDC8955DE4CC6D363670A47466E82BE5C23603A17BF22ACDB7CC984AF08C87E14E27753CF587A8EC3447E62C649E887A67C36C9CE98721B697213275646B194F36758673A8ED11284455AFC7A8529F69C97A3C2D7B8C636C0BA55614B768E624E712930F776169B01715725351BC74B47395ED52B25A1313C95164814C34C979CBDFAB85954662CAB485E75087A98CC74BB82CA2D1B5BF2803238480638C40E90B43C7460E7AA917F010151FAB1169987B372ABB59271F7006C24E60236B84B9DDD600623704254617FB498D89E58B0368BCB2103E79353EB587860C1422E476162E425BC2381DB82C6592737E1DD602864B0167A71EC1F223305C02FE25052AF2B3B5A55A0D7A2022D9A798DC0C5874A98702AAF4054C5D80338A5248B5B7BD09C53B5E2A084B047D277A861B1A73BB51488DE04EF573C85230A0470B73175C9FA50594F66A5F50B4150054C93B68186F8B5CBC49316C8548A642B2B36A1D454C7489AC33B2D2CE6668096782A2C1E0866D21A65E16B585E7AF8618BDF3184C1986878508917277B93E10706B1614972B2A94C7310FE9C708C231A1A8AC8D9314A529A97F469BF64962D820648443099A076D55D4CEA824A58304844F99497C10A25148618A315D72CA857D1B04D575B94F85C01D19BEF211BF0AA3362E7041FD16596D808E867B44C4C00D1CDA3418967717F147D0EB21B42AAEE74AC35D0B92414B958531AADF463EC6305AE5ECAF79174002F26DDECC813BF32672E8529D95A4E730A7AB4A3E8F8A8AF979A665EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922D4EC143B50F01423B177895EDEE22BB739F647ECF85F50BC25EF7B5A725DEE868626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F")
index 541bc1916f7a07dce4d1cde216b56a92f2077260..7dc1566df7e0aa186ea2af31618e73b40d05da27 100644 (file)
@@ -462,6 +462,7 @@ var depsRules = `
        < crypto/internal/fips/hmac
        < crypto/internal/fips/check
        < crypto/internal/fips/hkdf
+       < crypto/internal/fips/tls13
        < FIPS;
 
        FIPS < crypto/internal/fips/check/checktest;