From 681bfddd9d5b839abadbf14ca52e6884a4fa1aeb Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 1 Aug 2024 23:41:13 +0200 Subject: [PATCH 01/34] crypto/tls: fix testHandshake close flakes The flakes were introduced by me in CL 586655. It's unclear why only FreeBSD seems affected, maybe other TCP stacks handle sending on a half-closed connection differently, or aren't as quick to propagate the RST over localhost. Fixes #68155 Change-Id: I32a1b474a7d6531dbab93910c23568b867629e8c Reviewed-on: https://go-review.googlesource.com/c/go/+/602615 Reviewed-by: Cherry Mui Run-TryBot: Filippo Valsorda TryBot-Result: Gopher Robot Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: Go LUCI --- handshake_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/handshake_test.go b/handshake_test.go index bc3d23d..41c2643 100644 --- a/handshake_test.go +++ b/handshake_test.go @@ -491,9 +491,10 @@ func testHandshake(t *testing.T, clientConfig, serverConfig *Config) (serverStat if got := string(buf); got != sentinel { t.Errorf("read %q from TLS connection, but expected %q", got, sentinel) } - if err := cli.Close(); err != nil { - t.Errorf("failed to call cli.Close: %v", err) - } + // We discard the error because after ReadAll returns the server must + // have already closed the connection. Sending data (the closeNotify + // alert) can cause a reset, that will make Close return an error. + cli.Close() }() server := Server(s, serverConfig) err = server.Handshake() From 0d9e15f699805b0970afdc92d9b80d463a7b02d7 Mon Sep 17 00:00:00 2001 From: Bobby Powers Date: Sat, 25 Feb 2023 16:24:54 -0800 Subject: [PATCH 02/34] crypto/tls: expose extensions presented by client to GetCertificate This enables JA3 and JA4 TLS fingerprinting to be implemented from the GetCertificate callback, similar to what BoringSSL provides with its SSL_CTX_set_dos_protection_cb hook. fixes #32936 Change-Id: Idb54ebcb43075582fcef0ac6438727f494543424 Reviewed-on: https://go-review.googlesource.com/c/go/+/471396 Reviewed-by: Dmitri Shuralyov Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI --- common.go | 4 +++ handshake_messages.go | 3 ++ handshake_messages_test.go | 12 ++++++++ handshake_server.go | 1 + handshake_server_test.go | 60 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+) diff --git a/common.go b/common.go index 5fd92d3..dba9650 100644 --- a/common.go +++ b/common.go @@ -447,6 +447,10 @@ type ClientHelloInfo struct { // might be rejected if used. SupportedVersions []uint16 + // Extensions lists the IDs of the extensions presented by the client + // in the client hello. + Extensions []uint16 + // Conn is the underlying net.Conn for the connection. Do not read // from, or write to, this connection; that will cause the TLS // connection to fail. diff --git a/handshake_messages.go b/handshake_messages.go index 8620b66..823caff 100644 --- a/handshake_messages.go +++ b/handshake_messages.go @@ -97,6 +97,8 @@ type clientHelloMsg struct { pskBinders [][]byte quicTransportParameters []byte encryptedClientHello []byte + // extensions are only populated on the server-side of a handshake + extensions []uint16 } func (m *clientHelloMsg) marshalMsg(echInner bool) ([]byte, error) { @@ -467,6 +469,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return false } seenExts[extension] = true + m.extensions = append(m.extensions, extension) switch extension { case extensionServerName: diff --git a/handshake_messages_test.go b/handshake_messages_test.go index 197a1c5..2c360e6 100644 --- a/handshake_messages_test.go +++ b/handshake_messages_test.go @@ -76,6 +76,18 @@ func TestMarshalUnmarshal(t *testing.T) { m.activeCertHandles = nil } + if ch, ok := m.(*clientHelloMsg); ok { + // extensions is special cased, as it is only populated by the + // server-side of a handshake and is not expected to roundtrip + // through marshal + unmarshal. m ends up with the list of + // extensions necessary to serialize the other fields of + // clientHelloMsg, so check that it is non-empty, then clear it. + if len(ch.extensions) == 0 { + t.Errorf("expected ch.extensions to be populated on unmarshal") + } + ch.extensions = nil + } + // clientHelloMsg and serverHelloMsg, when unmarshalled, store // their original representation, for later use in the handshake // transcript. In order to prevent DeepEqual from failing since diff --git a/handshake_server.go b/handshake_server.go index ac3d915..bc4e51b 100644 --- a/handshake_server.go +++ b/handshake_server.go @@ -963,6 +963,7 @@ func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) SignatureSchemes: clientHello.supportedSignatureAlgorithms, SupportedProtos: clientHello.alpnProtocols, SupportedVersions: supportedVersions, + Extensions: clientHello.extensions, Conn: c.conn, config: c.config, ctx: ctx, diff --git a/handshake_server_test.go b/handshake_server_test.go index 94d3d0f..788a26a 100644 --- a/handshake_server_test.go +++ b/handshake_server_test.go @@ -23,6 +23,7 @@ import ( "runtime" "slices" "strings" + "sync/atomic" "testing" "time" ) @@ -1066,6 +1067,65 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) { runServerTestTLS12(t, test) } +// TestHandshakeServerGetCertificateExtensions tests to make sure that the +// Extensions passed to GetCertificate match what we expect based on the +// clientHelloMsg +func TestHandshakeServerGetCertificateExtensions(t *testing.T) { + const errMsg = "TestHandshakeServerGetCertificateExtensions error" + // ensure the test condition inside our GetCertificate callback + // is actually invoked + var called atomic.Int32 + + testVersions := []uint16{VersionTLS12, VersionTLS13} + for _, vers := range testVersions { + t.Run(fmt.Sprintf("TLS version %04x", vers), func(t *testing.T) { + pk, _ := ecdh.X25519().GenerateKey(rand.Reader) + clientHello := &clientHelloMsg{ + vers: vers, + random: make([]byte, 32), + cipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256}, + compressionMethods: []uint8{compressionNone}, + serverName: "test", + keyShares: []keyShare{{group: X25519, data: pk.PublicKey().Bytes()}}, + supportedCurves: []CurveID{X25519}, + supportedSignatureAlgorithms: []SignatureScheme{Ed25519}, + } + + // the clientHelloMsg initialized just above is serialized with + // two extensions: server_name(0) and application_layer_protocol_negotiation(16) + expectedExtensions := []uint16{ + extensionServerName, + extensionSupportedCurves, + extensionSignatureAlgorithms, + extensionKeyShare, + } + + if vers == VersionTLS13 { + clientHello.supportedVersions = []uint16{VersionTLS13} + expectedExtensions = append(expectedExtensions, extensionSupportedVersions) + } + + // Go's TLS client presents extensions in the ClientHello sorted by extension ID + slices.Sort(expectedExtensions) + + serverConfig := testConfig.Clone() + serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) { + if !slices.Equal(expectedExtensions, clientHello.Extensions) { + t.Errorf("expected extensions on ClientHelloInfo (%v) to match clientHelloMsg (%v)", expectedExtensions, clientHello.Extensions) + } + called.Add(1) + + return nil, errors.New(errMsg) + } + testClientHelloFailure(t, serverConfig, clientHello, errMsg) + }) + } + + if int(called.Load()) != len(testVersions) { + t.Error("expected our GetCertificate test to be called twice") + } +} + // TestHandshakeServerSNIGetCertificateError tests to make sure that errors in // GetCertificate result in a tls alert. func TestHandshakeServerSNIGetCertificateError(t *testing.T) { From 309a3593cdcce887cf434e8492e248faa852995c Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 14 Dec 2023 22:13:29 +0100 Subject: [PATCH 03/34] crypto/tls: align FIPS-only mode with BoringSSL policy This enables TLS 1.3, disables P-521, and disables non-ECDHE suites. Reapplies CL 549975. Updates #64717 Updates #62372 Change-Id: I6c608704638d59a063a657fbd4eb1126027112dd Reviewed-on: https://go-review.googlesource.com/c/go/+/603376 Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase --- boring_test.go | 70 +++++++++++++++++++++++++++------------ cipher_suites.go | 8 ++++- defaults.go | 8 ++--- handshake_client.go | 9 +++-- handshake_client_tls13.go | 4 --- handshake_server_test.go | 1 + handshake_server_tls13.go | 7 ++-- 7 files changed, 70 insertions(+), 37 deletions(-) diff --git a/boring_test.go b/boring_test.go index be10b71..5605042 100644 --- a/boring_test.go +++ b/boring_test.go @@ -25,6 +25,31 @@ import ( "time" ) +func allCipherSuitesIncludingTLS13() []uint16 { + s := allCipherSuites() + for _, suite := range cipherSuitesTLS13 { + s = append(s, suite.id) + } + return s +} + +func isTLS13CipherSuite(id uint16) bool { + for _, suite := range cipherSuitesTLS13 { + if id == suite.id { + return true + } + } + return false +} + +func generateKeyShare(group CurveID) keyShare { + key, err := generateECDHEKey(rand.Reader, group) + if err != nil { + panic(err) + } + return keyShare{group: group, data: key.PublicKey().Bytes()} +} + func TestBoringServerProtocolVersion(t *testing.T) { test := func(t *testing.T, name string, v uint16, msg string) { t.Run(name, func(t *testing.T) { @@ -60,22 +85,22 @@ func TestBoringServerProtocolVersion(t *testing.T) { test(t, "VersionTLS10", VersionTLS10, "supported versions") test(t, "VersionTLS11", VersionTLS11, "supported versions") test(t, "VersionTLS12", VersionTLS12, "") - test(t, "VersionTLS13", VersionTLS13, "supported versions") + test(t, "VersionTLS13", VersionTLS13, "") }) } func isBoringVersion(v uint16) bool { - return v == VersionTLS12 + return v == VersionTLS12 || v == VersionTLS13 } func isBoringCipherSuite(id uint16) bool { switch id { - case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + case TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS_RSA_WITH_AES_128_GCM_SHA256, - TLS_RSA_WITH_AES_256_GCM_SHA384: + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: return true } return false @@ -83,7 +108,7 @@ func isBoringCipherSuite(id uint16) bool { func isBoringCurve(id CurveID) bool { switch id { - case CurveP256, CurveP384, CurveP521: + case CurveP256, CurveP384: return true } return false @@ -95,7 +120,7 @@ func isECDSA(id uint16) bool { return suite.flags&suiteECSign == suiteECSign } } - panic(fmt.Sprintf("unknown cipher suite %#x", id)) + return false // TLS 1.3 cipher suites are not tied to the signature algorithm. } func isBoringSignatureScheme(alg SignatureScheme) bool { @@ -107,7 +132,6 @@ func isBoringSignatureScheme(alg SignatureScheme) bool { PKCS1WithSHA384, ECDSAWithP384AndSHA384, PKCS1WithSHA512, - ECDSAWithP521AndSHA512, PSSWithSHA256, PSSWithSHA384, PSSWithSHA512: @@ -118,10 +142,9 @@ func isBoringSignatureScheme(alg SignatureScheme) bool { func TestBoringServerCipherSuites(t *testing.T) { serverConfig := testConfig.Clone() - serverConfig.CipherSuites = allCipherSuites() serverConfig.Certificates = make([]Certificate, 1) - for _, id := range allCipherSuites() { + for _, id := range allCipherSuitesIncludingTLS13() { if isECDSA(id) { serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey @@ -130,14 +153,20 @@ func TestBoringServerCipherSuites(t *testing.T) { serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey } serverConfig.BuildNameToCertificate() - t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) { + t.Run(fmt.Sprintf("suite=%s", CipherSuiteName(id)), func(t *testing.T) { clientHello := &clientHelloMsg{ - vers: VersionTLS12, - random: make([]byte, 32), - cipherSuites: []uint16{id}, - compressionMethods: []uint8{compressionNone}, - supportedCurves: defaultCurvePreferences(), - supportedPoints: []uint8{pointFormatUncompressed}, + vers: VersionTLS12, + random: make([]byte, 32), + cipherSuites: []uint16{id}, + compressionMethods: []uint8{compressionNone}, + supportedCurves: defaultCurvePreferences(), + keyShares: []keyShare{generateKeyShare(CurveP256)}, + supportedPoints: []uint8{pointFormatUncompressed}, + supportedVersions: []uint16{VersionTLS12}, + supportedSignatureAlgorithms: defaultSupportedSignatureAlgorithmsFIPS, + } + if isTLS13CipherSuite(id) { + clientHello.supportedVersions = []uint16{VersionTLS13} } testClientHello(t, serverConfig, clientHello) @@ -156,9 +185,6 @@ func TestBoringServerCipherSuites(t *testing.T) { func TestBoringServerCurves(t *testing.T) { serverConfig := testConfig.Clone() - serverConfig.Certificates = make([]Certificate, 1) - serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} - serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey serverConfig.BuildNameToCertificate() for _, curveid := range defaultCurvePreferences() { @@ -288,7 +314,7 @@ func TestBoringClientHello(t *testing.T) { } if !isBoringVersion(hello.vers) { - t.Errorf("client vers=%#x, want %#x (TLS 1.2)", hello.vers, VersionTLS12) + t.Errorf("client vers=%#x", hello.vers) } for _, v := range hello.supportedVersions { if !isBoringVersion(v) { diff --git a/cipher_suites.go b/cipher_suites.go index eebc668..917a1ef 100644 --- a/cipher_suites.go +++ b/cipher_suites.go @@ -552,7 +552,13 @@ func aeadAESGCMTLS13(key, nonceMask []byte) aead { if err != nil { panic(err) } - aead, err := cipher.NewGCM(aes) + var aead cipher.AEAD + if boring.Enabled { + aead, err = boring.NewGCMTLS13(aes) + } else { + boring.Unreachable() + aead, err = cipher.NewGCM(aes) + } if err != nil { panic(err) } diff --git a/defaults.go b/defaults.go index 9b28acd..ad4070d 100644 --- a/defaults.go +++ b/defaults.go @@ -90,13 +90,16 @@ var defaultCipherSuitesTLS13NoAES = []uint16{ TLS_AES_256_GCM_SHA384, } +// The FIPS-only policies below match BoringSSL's ssl_policy_fips_202205. + var defaultSupportedVersionsFIPS = []uint16{ VersionTLS12, + VersionTLS13, } // defaultCurvePreferencesFIPS are the FIPS-allowed curves, // in preference order (most preferable first). -var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384, CurveP521} +var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384} // defaultSupportedSignatureAlgorithmsFIPS currently are a subset of // defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1. @@ -109,7 +112,6 @@ var defaultSupportedSignatureAlgorithmsFIPS = []SignatureScheme{ PKCS1WithSHA384, ECDSAWithP384AndSHA384, PKCS1WithSHA512, - ECDSAWithP521AndSHA512, } // defaultCipherSuitesFIPS are the FIPS-allowed cipher suites. @@ -118,8 +120,6 @@ var defaultCipherSuitesFIPS = []uint16{ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS_RSA_WITH_AES_128_GCM_SHA256, - TLS_RSA_WITH_AES_256_GCM_SHA384, } // defaultCipherSuitesTLS13FIPS are the FIPS-allowed cipher suites for TLS 1.3. diff --git a/handshake_client.go b/handshake_client.go index 5025657..760e827 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -141,13 +141,18 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon if len(hello.supportedVersions) == 1 { hello.cipherSuites = nil } - if hasAESGCMHardwareSupport { + if needFIPS() { + hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13FIPS...) + } else if hasAESGCMHardwareSupport { hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...) } else { hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...) } - curveID := config.curvePreferences(maxVersion)[0] + if len(hello.supportedCurves) == 0 { + return nil, nil, nil, errors.New("tls: no supported elliptic curves for ECDHE") + } + curveID := hello.supportedCurves[0] keyShareKeys = &keySharePrivateKeys{curveID: curveID} if curveID == x25519Kyber768Draft00 { keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), X25519) diff --git a/handshake_client_tls13.go b/handshake_client_tls13.go index db5e35d..21a501f 100644 --- a/handshake_client_tls13.go +++ b/handshake_client_tls13.go @@ -45,10 +45,6 @@ type clientHandshakeStateTLS13 struct { func (hs *clientHandshakeStateTLS13) handshake() error { c := hs.c - if needFIPS() { - return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode") - } - // The server must not select TLS 1.3 in a renegotiation. See RFC 8446, // sections 4.1.2 and 4.1.3. if c.handshakes > 0 { diff --git a/handshake_server_test.go b/handshake_server_test.go index 788a26a..01eae15 100644 --- a/handshake_server_test.go +++ b/handshake_server_test.go @@ -29,6 +29,7 @@ import ( ) func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) { + t.Helper() testClientHelloFailure(t, serverConfig, m, "") } diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index 503a732..b8cf4c3 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -47,10 +47,6 @@ type serverHandshakeStateTLS13 struct { func (hs *serverHandshakeStateTLS13) handshake() error { c := hs.c - if needFIPS() { - return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode") - } - // For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2. if err := hs.processClientHello(); err != nil { return err @@ -165,6 +161,9 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) { preferenceList = defaultCipherSuitesTLS13NoAES } + if needFIPS() { + preferenceList = defaultCipherSuitesTLS13FIPS + } for _, suiteID := range preferenceList { hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID) if hs.suite != nil { From 478fdf19778f9fa58ccf7bf293c41916e10288c0 Mon Sep 17 00:00:00 2001 From: Clide Stefani Date: Tue, 25 Jun 2024 15:52:32 -0400 Subject: [PATCH 04/34] crypto/tls: add support for additional alpn flags to bogo_shim_test The existing implementation of bogo_shim_test does not support tests that use the -expect-advertised-alpn flag or the -select-alpn flag. This change allows bogo_shim_test to receive and enforce these flags. Support for these flags is added in the same change because these flags are set together. Updates #51434 Change-Id: Ia37f9e7403d4a43e6da68c16039a4bcb56ebd032 Reviewed-on: https://go-review.googlesource.com/c/go/+/595655 Auto-Submit: Filippo Valsorda Reviewed-by: Carlos Amedee Reviewed-by: Russell Webb Reviewed-by: Clide Stefani LUCI-TryBot-Result: Go LUCI Auto-Submit: Roland Shoemaker Reviewed-by: Roland Shoemaker --- bogo_shim_test.go | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/bogo_shim_test.go b/bogo_shim_test.go index ce01852..ff836d9 100644 --- a/bogo_shim_test.go +++ b/bogo_shim_test.go @@ -17,9 +17,12 @@ import ( "os/exec" "path/filepath" "runtime" + "slices" "strconv" "strings" "testing" + + "golang.org/x/crypto/cryptobyte" ) var ( @@ -77,10 +80,12 @@ var ( _ = flag.Bool("expect-ticket-supports-early-data", false, "") onResumeShimWritesFirst = flag.Bool("on-resume-shim-writes-first", false, "") - advertiseALPN = flag.String("advertise-alpn", "", "") - expectALPN = flag.String("expect-alpn", "", "") - rejectALPN = flag.Bool("reject-alpn", false, "") - declineALPN = flag.Bool("decline-alpn", false, "") + advertiseALPN = flag.String("advertise-alpn", "", "") + expectALPN = flag.String("expect-alpn", "", "") + rejectALPN = flag.Bool("reject-alpn", false, "") + declineALPN = flag.Bool("decline-alpn", false, "") + expectAdvertisedALPN = flag.String("expect-advertised-alpn", "", "") + selectALPN = flag.String("select-alpn", "", "") hostName = flag.String("host-name", "", "") @@ -118,6 +123,29 @@ func bogoShim() { MaxVersion: uint16(*maxVersion), ClientSessionCache: NewLRUClientSessionCache(0), + + GetConfigForClient: func(chi *ClientHelloInfo) (*Config, error) { + + if *expectAdvertisedALPN != "" { + + s := cryptobyte.String(*expectAdvertisedALPN) + + var expectedALPNs []string + + for !s.Empty() { + var alpn cryptobyte.String + if !s.ReadUint8LengthPrefixed(&alpn) { + return nil, fmt.Errorf("unexpected error while parsing arguments for -expect-advertised-alpn") + } + expectedALPNs = append(expectedALPNs, string(alpn)) + } + + if !slices.Equal(chi.SupportedProtos, expectedALPNs) { + return nil, fmt.Errorf("unexpected ALPN: got %q, want %q", chi.SupportedProtos, expectedALPNs) + } + } + return nil, nil + }, } if *noTLS1 { @@ -160,6 +188,9 @@ func bogoShim() { if *declineALPN { cfg.NextProtos = []string{} } + if *selectALPN != "" { + cfg.NextProtos = []string{*selectALPN} + } if *hostName != "" { cfg.ServerName = *hostName @@ -288,6 +319,11 @@ func bogoShim() { if *expectALPN != "" && cs.NegotiatedProtocol != *expectALPN { log.Fatalf("unexpected protocol negotiated: want %q, got %q", *expectALPN, cs.NegotiatedProtocol) } + + if *selectALPN != "" && cs.NegotiatedProtocol != *selectALPN { + log.Fatalf("unexpected protocol negotiated: want %q, got %q", *selectALPN, cs.NegotiatedProtocol) + } + if *expectVersion != 0 && cs.Version != uint16(*expectVersion) { log.Fatalf("expected ssl version %q, got %q", uint16(*expectVersion), cs.Version) } From 91b914d5f250cc3fab097dc966684350940ca0b3 Mon Sep 17 00:00:00 2001 From: Jaeho Nam Date: Wed, 7 Aug 2024 06:14:11 +0000 Subject: [PATCH 05/34] crypto/tls: fix typo in quicError Change-Id: I2c07592c3b896bc86e349de7c032929b9979349c GitHub-Last-Rev: 0fe8b90e09b971821f9b0c0a528ed61895d3d110 GitHub-Pull-Request: golang/go#68757 Reviewed-on: https://go-review.googlesource.com/c/go/+/603517 Reviewed-by: Jorropo Auto-Submit: Damien Neil LUCI-TryBot-Result: Go LUCI Reviewed-by: Damien Neil Reviewed-by: Carlos Amedee --- quic.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quic.go b/quic.go index 9dd6168..ba8a235 100644 --- a/quic.go +++ b/quic.go @@ -206,7 +206,7 @@ func (q *QUICConn) Start(ctx context.Context) error { } q.conn.quic.started = true if q.conn.config.MinVersion < VersionTLS13 { - return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.13")) + return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.3")) } go q.conn.HandshakeContext(ctx) if _, ok := <-q.conn.quic.blockedc; !ok { From c5561373ff8315116c9cb23593bc8894f71e9892 Mon Sep 17 00:00:00 2001 From: apocelipes Date: Wed, 14 Aug 2024 03:49:33 +0000 Subject: [PATCH 06/34] crypto,hash: add t.Helper calls to test helpers Use t.Helper to make the reported failure lines more helpful. Change-Id: I6593924b3892b2441a197aee4e05f71ea236d426 GitHub-Last-Rev: 2e020ea85cf44c6cc0e90cb919eb0d7bb5a1c315 GitHub-Pull-Request: golang/go#68843 Reviewed-on: https://go-review.googlesource.com/c/go/+/604755 Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Reviewed-by: Carlos Amedee LUCI-TryBot-Result: Go LUCI --- tls_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/tls_test.go b/tls_test.go index fc50406..a6c0336 100644 --- a/tls_test.go +++ b/tls_test.go @@ -163,6 +163,7 @@ func TestX509MixedKeyPair(t *testing.T) { } func newLocalListener(t testing.TB) net.Listener { + t.Helper() ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { ln, err = net.Listen("tcp6", "[::1]:0") From 2811331d5dfafd6cbe4fc28faa28993f3b19ab0b Mon Sep 17 00:00:00 2001 From: Ryan Granger Date: Fri, 11 Oct 2024 16:53:56 +0000 Subject: [PATCH 07/34] crypto/tls: include close notify in client tls test recordings This commit fixes the issue where tls testdata recordings made with the newer version of the prerecorded tls conversation test harness, doesn't end up capturing the final close notify message. The fix simply ensures that the tls.Client closes before the recording of the conversation is closed. The closing of the client connection directly is no longer needed when updating the recording since it will be closed when the tls.Client is closed. Fixes golang/go#69846 Change-Id: I93898de32abd89659a32ed240df6daea5aeaa7fc Reviewed-on: https://go-review.googlesource.com/c/go/+/620395 Reviewed-by: Michael Knyszek Reviewed-by: Filippo Valsorda Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- handshake_client_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handshake_client_test.go b/handshake_client_test.go index 501f9c6..c001822 100644 --- a/handshake_client_test.go +++ b/handshake_client_test.go @@ -433,7 +433,7 @@ func (test *clientTest) run(t *testing.T, write bool) { } if write { - clientConn.Close() + client.Close() path := test.dataPath() out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { From bc7af2145196d65a06a027f98ad2a109c56bc685 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sun, 3 Nov 2024 10:03:21 +0100 Subject: [PATCH 08/34] crypto/internal/fips/aes: move GCM to its own package For #69536 Change-Id: Idcef2411c1fd4da302412609f28e438839e8aa4b Reviewed-on: https://go-review.googlesource.com/c/go/+/624736 LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov Auto-Submit: Filippo Valsorda --- cipher_suites.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cipher_suites.go b/cipher_suites.go index 917a1ef..ec867ce 100644 --- a/cipher_suites.go +++ b/cipher_suites.go @@ -365,15 +365,13 @@ var tdesCiphers = map[uint16]bool{ } var ( - hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ + // Keep in sync with crypto/internal/fips/aes/gcm.supportsAESGCM. + hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41 && cpu.X86.HasSSSE3 hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL - // Keep in sync with crypto/aes/cipher_s390x.go. - hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && - (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM) + hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCTR && cpu.S390X.HasGHASH + hasGCMAsmPPC64 = runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" - hasAESGCMHardwareSupport = runtime.GOARCH == "amd64" && hasGCMAsmAMD64 || - runtime.GOARCH == "arm64" && hasGCMAsmARM64 || - runtime.GOARCH == "s390x" && hasGCMAsmS390X + hasAESGCMHardwareSupport = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X || hasGCMAsmPPC64 ) var aesgcmCiphers = map[uint16]bool{ From b06b8816fa00d57d056881950eb3a9d9ceea1297 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Fri, 8 Nov 2024 19:56:50 +0100 Subject: [PATCH 09/34] crypto/internal/fips/aes/gcm: add GCMForTLS12 and GCMForTLS13 For #69536 Change-Id: I2d7b6e7b9932d0f0f582a5ab0bb871395dc2a1e8 Reviewed-on: https://go-review.googlesource.com/c/go/+/626675 LUCI-TryBot-Result: Go LUCI Reviewed-by: Daniel McCarney Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov Auto-Submit: Filippo Valsorda --- cipher_suites.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cipher_suites.go b/cipher_suites.go index ec867ce..1c849e3 100644 --- a/cipher_suites.go +++ b/cipher_suites.go @@ -11,6 +11,8 @@ import ( "crypto/des" "crypto/hmac" "crypto/internal/boring" + fipsaes "crypto/internal/fips/aes" + "crypto/internal/fips/aes/gcm" "crypto/rc4" "crypto/sha1" "crypto/sha256" @@ -521,7 +523,7 @@ func aeadAESGCM(key, noncePrefix []byte) aead { aead, err = boring.NewGCMTLS(aes) } else { boring.Unreachable() - aead, err = cipher.NewGCM(aes) + aead, err = gcm.NewGCMForTLS12(aes.(*fipsaes.Block)) } if err != nil { panic(err) @@ -555,7 +557,7 @@ func aeadAESGCMTLS13(key, nonceMask []byte) aead { aead, err = boring.NewGCMTLS13(aes) } else { boring.Unreachable() - aead, err = cipher.NewGCM(aes) + aead, err = gcm.NewGCMForTLS13(aes.(*fipsaes.Block)) } if err != nil { panic(err) From 80b8ff4aa980739cf600bf2d2645198cd3850451 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sat, 9 Nov 2024 16:23:22 +0100 Subject: [PATCH 10/34] crypto/internal/fips/tls13: implement TLS 1.3 KDF 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 Reviewed-by: Roland Shoemaker Commit-Queue: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney --- handshake_client.go | 9 +- handshake_client_tls13.go | 39 ++++---- handshake_server_tls13.go | 38 ++++---- key_schedule.go | 84 ++--------------- key_schedule_test.go | 192 ++++++++++++++------------------------ 5 files changed, 114 insertions(+), 248 deletions(-) diff --git a/handshake_client.go b/handshake_client.go index 760e827..f6bccc4 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -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 diff --git a/handshake_client_tls13.go b/handshake_client_tls13.go index 21a501f..cdef806 100644 --- a/handshake_client_tls13.go +++ b/handshake_client_tls13.go @@ -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() diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index b8cf4c3..29add50 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -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) diff --git a/key_schedule.go b/key_schedule.go index 1636baf..9c76ebe 100644 --- a/key_schedule.go +++ b/key_schedule.go @@ -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 } } diff --git a/key_schedule_test.go b/key_schedule_test.go index 3ffdf6c..02187e7 100644 --- a/key_schedule_test.go +++ b/key_schedule_test.go @@ -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") From beed2c67b07f15442157bc8c20b906cc468dcf71 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sat, 9 Nov 2024 17:21:42 +0100 Subject: [PATCH 11/34] crypto/internal/fips/tls12: implement TLS 1.2 KDF For #69536 Change-Id: If2477c5249a7c7db45c1af05e715ae0b61e7d940 Reviewed-on: https://go-review.googlesource.com/c/go/+/626837 Reviewed-by: Roland Shoemaker Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Michael Knyszek Reviewed-by: Russ Cox --- prf.go | 63 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/prf.go b/prf.go index a7fa337..c306ca4 100644 --- a/prf.go +++ b/prf.go @@ -7,6 +7,7 @@ package tls import ( "crypto" "crypto/hmac" + "crypto/internal/fips/tls12" "crypto/md5" "crypto/sha1" "crypto/sha256" @@ -16,6 +17,8 @@ import ( "hash" ) +type prfFunc func(secret []byte, label string, seed []byte, keyLen int) []byte + // Split a premaster secret in two as specified in RFC 4346, Section 5. func splitPreMasterSecret(secret []byte) (s1, s2 []byte) { s1 = secret[0 : (len(secret)+1)/2] @@ -45,7 +48,8 @@ func pHash(result, secret, seed []byte, hash func() hash.Hash) { } // prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, Section 5. -func prf10(result, secret, label, seed []byte) { +func prf10(secret []byte, label string, seed []byte, keyLen int) []byte { + result := make([]byte, keyLen) hashSHA1 := sha1.New hashMD5 := md5.New @@ -61,16 +65,14 @@ func prf10(result, secret, label, seed []byte) { for i, b := range result2 { result[i] ^= b } + + return result } // prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, Section 5. -func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) { - return func(result, secret, label, seed []byte) { - labelAndSeed := make([]byte, len(label)+len(seed)) - copy(labelAndSeed, label) - copy(labelAndSeed[len(label):], seed) - - pHash(result, secret, labelAndSeed, hashFunc) +func prf12(hashFunc func() hash.Hash) prfFunc { + return func(secret []byte, label string, seed []byte, keyLen int) []byte { + return tls12.PRF(hashFunc, secret, label, seed, keyLen) } } @@ -79,13 +81,13 @@ const ( finishedVerifyLength = 12 // Length of verify_data in a Finished message. ) -var masterSecretLabel = []byte("master secret") -var extendedMasterSecretLabel = []byte("extended master secret") -var keyExpansionLabel = []byte("key expansion") -var clientFinishedLabel = []byte("client finished") -var serverFinishedLabel = []byte("server finished") +const masterSecretLabel = "master secret" +const extendedMasterSecretLabel = "extended master secret" +const keyExpansionLabel = "key expansion" +const clientFinishedLabel = "client finished" +const serverFinishedLabel = "server finished" -func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) { +func prfAndHashForVersion(version uint16, suite *cipherSuite) (prfFunc, crypto.Hash) { switch version { case VersionTLS10, VersionTLS11: return prf10, crypto.Hash(0) @@ -99,7 +101,7 @@ func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secr } } -func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) { +func prfForVersion(version uint16, suite *cipherSuite) prfFunc { prf, _ := prfAndHashForVersion(version, suite) return prf } @@ -111,17 +113,19 @@ func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecr seed = append(seed, clientRandom...) seed = append(seed, serverRandom...) - masterSecret := make([]byte, masterSecretLength) - prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed) - return masterSecret + return prfForVersion(version, suite)(preMasterSecret, masterSecretLabel, seed, masterSecretLength) } // extMasterFromPreMasterSecret generates the extended master secret from the // pre-master secret. See RFC 7627. func extMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, transcript []byte) []byte { - masterSecret := make([]byte, masterSecretLength) - prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, transcript) - return masterSecret + prf, hash := prfAndHashForVersion(version, suite) + if version == VersionTLS12 { + // Use the FIPS 140-3 module only for TLS 1.2 with EMS, which is the + // only TLS 1.0-1.2 approved mode per IG D.Q. + return tls12.MasterSecret(hash.New, preMasterSecret, transcript) + } + return prf(preMasterSecret, extendedMasterSecretLabel, transcript, masterSecretLength) } // keysFromMasterSecret generates the connection keys from the master @@ -133,8 +137,7 @@ func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clie seed = append(seed, clientRandom...) n := 2*macLen + 2*keyLen + 2*ivLen - keyMaterial := make([]byte, n) - prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed) + keyMaterial := prfForVersion(version, suite)(masterSecret, keyExpansionLabel, seed, n) clientMAC = keyMaterial[:macLen] keyMaterial = keyMaterial[macLen:] serverMAC = keyMaterial[:macLen] @@ -177,7 +180,7 @@ type finishedHash struct { buffer []byte version uint16 - prf func(result, secret, label, seed []byte) + prf prfFunc } func (h *finishedHash) Write(msg []byte) (n int, err error) { @@ -209,17 +212,13 @@ func (h finishedHash) Sum() []byte { // clientSum returns the contents of the verify_data member of a client's // Finished message. func (h finishedHash) clientSum(masterSecret []byte) []byte { - out := make([]byte, finishedVerifyLength) - h.prf(out, masterSecret, clientFinishedLabel, h.Sum()) - return out + return h.prf(masterSecret, clientFinishedLabel, h.Sum(), finishedVerifyLength) } // serverSum returns the contents of the verify_data member of a server's // Finished message. func (h finishedHash) serverSum(masterSecret []byte) []byte { - out := make([]byte, finishedVerifyLength) - h.prf(out, masterSecret, serverFinishedLabel, h.Sum()) - return out + return h.prf(masterSecret, serverFinishedLabel, h.Sum(), finishedVerifyLength) } // hashForClientCertificate returns the handshake messages so far, pre-hashed if @@ -292,8 +291,6 @@ func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clien seed = append(seed, context...) } - keyMaterial := make([]byte, length) - prfForVersion(version, suite)(keyMaterial, masterSecret, []byte(label), seed) - return keyMaterial, nil + return prfForVersion(version, suite)(masterSecret, label, seed, length), nil } } From 3d4d31065bb7c5312e3a6ba97d81d92abbb6da02 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sat, 12 Oct 2024 20:22:44 +0200 Subject: [PATCH 12/34] crypto/internal/mlkem768: update to final FIPS 203 Main changes are the domain separator in KeyGen, dropping support for the extended decapsulation key encoding in favor of seeds (see https://words.filippo.io/ml-kem-seeds/), and documentation changes. Change-Id: I8773034929094b3242aa39ac6e9d007c2bc94e63 Reviewed-on: https://go-review.googlesource.com/c/go/+/621975 Reviewed-by: Daniel McCarney Auto-Submit: Filippo Valsorda Reviewed-by: Russ Cox Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI --- key_schedule_test.go | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/key_schedule_test.go b/key_schedule_test.go index 02187e7..095113c 100644 --- a/key_schedule_test.go +++ b/key_schedule_test.go @@ -119,24 +119,6 @@ func TestTrafficKey(t *testing.T) { } } -func TestKyberDecapsulate(t *testing.T) { - // From https://pq-crystals.org/kyber/data/kyber-submission-nist-round3.zip - dkBytes, _ := hex.DecodeString("07638FB69868F3D320E5862BD96933FEB311B362093C9B5D50170BCED43F1B536D9A204BB1F22695950BA1F2A9E8EB828B284488760B3FC84FABA04275D5628E39C5B2471374283C503299C0AB49B66B8BBB56A4186624F919A2BA59BB08D8551880C2BEFC4F87F25F59AB587A79C327D792D54C974A69262FF8A78938289E9A87B688B083E0595FE218B6BB1505941CE2E81A5A64C5AAC60417256985349EE47A52420A5F97477B7236AC76BC70E8288729287EE3E34A3DBC3683C0B7B10029FC203418537E7466BA6385A8FF301EE12708F82AAA1E380FC7A88F8F205AB7E88D7E95952A55BA20D09B79A47141D62BF6EB7DD307B08ECA13A5BC5F6B68581C6865B27BBCDDAB142F4B2CBFF488C8A22705FAA98A2B9EEA3530C76662335CC7EA3A00777725EBCCCD2A4636B2D9122FF3AB77123CE0883C1911115E50C9E8A94194E48DD0D09CFFB3ADCD2C1E92430903D07ADBF00532031575AA7F9E7B5A1F3362DEC936D4043C05F2476C07578BC9CBAF2AB4E382727AD41686A96B2548820BB03B32F11B2811AD62F489E951632ABA0D1DF89680CC8A8B53B481D92A68D70B4EA1C3A6A561C0692882B5CA8CC942A8D495AFCB06DE89498FB935B775908FE7A03E324D54CC19D4E1AABD3593B38B19EE1388FE492B43127E5A504253786A0D69AD32601C28E2C88504A5BA599706023A61363E17C6B9BB59BDC697452CD059451983D738CA3FD034E3F5988854CA05031DB09611498988197C6B30D258DFE26265541C89A4B31D6864E9389B03CB74F7EC4323FB9421A4B9790A26D17B0398A26767350909F84D57B6694DF830664CA8B3C3C03ED2AE67B89006868A68527CCD666459AB7F056671000C6164D3A7F266A14D97CBD7004D6C92CACA770B844A4FA9B182E7B18CA885082AC5646FCB4A14E1685FEB0C9CE3372AB95365C04FD83084F80A23FF10A05BF15F7FA5ACC6C0CB462C33CA524FA6B8BB359043BA68609EAA2536E81D08463B19653B5435BA946C9ADDEB202B04B031CC960DCC12E4518D428B32B257A4FC7313D3A7980D80082E934F9D95C32B0A0191A23604384DD9E079BBBAA266D14C3F756B9F2133107433A4E83FA7187282A809203A4FAF841851833D121AC383843A5E55BC2381425E16C7DB4CC9AB5C1B0D91A47E2B8DE0E582C86B6B0D907BB360B97F40AB5D038F6B75C814B27D9B968D419832BC8C2BEE605EF6E5059D33100D90485D378450014221736C07407CAC260408AA64926619788B8601C2A752D1A6CBF820D7C7A04716203225B3895B9342D147A8185CFC1BB65BA06B4142339903C0AC4651385B45D98A8B19D28CD6BAB088787F7EE1B12461766B43CBCCB96434427D93C065550688F6948ED1B5475A425F1B85209D061C08B56C1CC069F6C0A7C6F29358CAB911087732A649D27C9B98F9A48879387D9B00C25959A71654D6F6A946164513E47A75D005986C2363C09F6B537ECA78B9303A5FA457608A586A653A347DB04DFCC19175B3A301172536062A658A95277570C8852CA8973F4AE123A334047DD711C8927A634A03388A527B034BF7A8170FA702C1F7C23EC32D18A2374890BE9C787A9409C82D192C4BB705A2F996CE405DA72C2D9C843EE9F8313ECC7F86D6294D59159D9A879A542E260922ADF999051CC45200C9FFDB60449C49465979272367C083A7D6267A3ED7A7FD47957C219327F7CA73A4007E1627F00B11CC80573C15AEE6640FB8562DFA6B240CA0AD351AC4AC155B96C14C8AB13DD262CDFD51C4BB5572FD616553D17BDD430ACBEA3E95F0B698D66990AB51E5D03783A8B3D278A5720454CF9695CFDCA08485BA099C51CD92A7EA7587C1D15C28E609A81852601B0604010679AA482D51261EC36E36B8719676217FD74C54786488F4B4969C05A8BA27CA3A77CCE73B965923CA554E422B9B61F4754641608AC16C9B8587A32C1C5DD788F88B36B717A46965635DEB67F45B129B99070909C93EB80B42C2B3F3F70343A7CF37E8520E7BCFC416ACA4F18C7981262BA2BFC756AE03278F0EC66DC2057696824BA6769865A601D7148EF6F54E5AF5686AA2906F994CE38A5E0B938F239007003022C03392DF3401B1E4A3A7EBC6161449F73374C8B0140369343D9295FDF511845C4A46EBAAB6CA5492F6800B98C0CC803653A4B1D6E6AAED1932BACC5FEFAA818BA502859BA5494C5F5402C8536A9C4C1888150617F80098F6B2A99C39BC5DC7CF3B5900A21329AB59053ABAA64ED163E859A8B3B3CA3359B750CCC3E710C7AC43C8191CB5D68870C06391C0CB8AEC72B897AC6BE7FBAACC676ED66314C83630E89448C88A1DF04ACEB23ABF2E409EF333C622289C18A2134E650C45257E47475FA33AA537A5A8F7680214716C50D470E3284963CA64F54677AEC54B5272162BF52BC8142E1D4183FC017454A6B5A496831759064024745978CBD51A6CEDC8955DE4CC6D363670A47466E82BE5C23603A17BF22ACDB7CC984AF08C87E14E27753CF587A8EC3447E62C649E887A67C36C9CE98721B697213275646B194F36758673A8ED11284455AFC7A8529F69C97A3C2D7B8C636C0BA55614B768E624E712930F776169B01715725351BC74B47395ED52B25A1313C95164814C34C979CBDFAB85954662CAB485E75087A98CC74BB82CA2D1B5BF2803238480638C40E90B43C7460E7AA917F010151FAB1169987B372ABB59271F7006C24E60236B84B9DDD600623704254617FB498D89E58B0368BCB2103E79353EB587860C1422E476162E425BC2381DB82C6592737E1DD602864B0167A71EC1F223305C02FE25052AF2B3B5A55A0D7A2022D9A798DC0C5874A98702AAF4054C5D80338A5248B5B7BD09C53B5E2A084B047D277A861B1A73BB51488DE04EF573C85230A0470B73175C9FA50594F66A5F50B4150054C93B68186F8B5CBC49316C8548A642B2B36A1D454C7489AC33B2D2CE6668096782A2C1E0866D21A65E16B585E7AF8618BDF3184C1986878508917277B93E10706B1614972B2A94C7310FE9C708C231A1A8AC8D9314A529A97F469BF64962D820648443099A076D55D4CEA824A58304844F99497C10A25148618A315D72CA857D1B04D575B94F85C01D19BEF211BF0AA3362E7041FD16596D808E867B44C4C00D1CDA3418967717F147D0EB21B42AAEE74AC35D0B92414B958531AADF463EC6305AE5ECAF79174002F26DDECC813BF32672E8529D95A4E730A7AB4A3E8F8A8AF979A665EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922D4EC143B50F01423B177895EDEE22BB739F647ECF85F50BC25EF7B5A725DEE868626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F") - dk, err := mlkem768.NewKeyFromExtendedEncoding(dkBytes) - if err != nil { - t.Fatal(err) - } - ct, _ := hex.DecodeString("B52C56B92A4B7CE9E4CB7C5B1B163167A8A1675B2FDEF84A5B67CA15DB694C9F11BD027C30AE22EC921A1D911599AF0585E48D20DA70DF9F39E32EF95D4C8F44BFEFDAA5DA64F1054631D04D6D3CFD0A540DD7BA3886E4B5F13E878788604C95C096EAB3919F427521419A946C26CC041475D7124CDC01D0373E5B09C7A70603CFDB4FB3405023F2264DC3F983C4FC02A2D1B268F2208A1F6E2A6209BFF12F6F465F0B069C3A7F84F606D8A94064003D6EC114C8E808D3053884C1D5A142FBF20112EB360FDA3F0F28B172AE50F5E7D83801FB3F0064B687187074BD7FE30EDDAA334CF8FC04FA8CED899CEADE4B4F28B68372BAF98FF482A415B731155B75CEB976BE0EA0285BA01A27F1857A8FB377A3AE0C23B2AA9A079BFABFF0D5B2F1CD9B718BEA03C42F343A39B4F142D01AD8ACBB50E38853CF9A50C8B44C3CF671A4A9043B26DDBB24959AD6715C08521855C79A23B9C3D6471749C40725BDD5C2776D43AED20204BAA141EFB3304917474B7F9F7A4B08B1A93DAED98C67495359D37D67F7438BEE5E43585634B26C6B3810D7CDCBC0F6EB877A6087E68ACB8480D3A8CF6900447E49B417F15A53B607A0E216B855970D37406870B4568722DA77A4084703816784E2F16BED18996532C5D8B7F5D214464E5F3F6E905867B0CE119E252A66713253544685D208E1723908A0CE97834652E08AE7BDC881A131B73C71E84D20D68FDEFF4F5D70CD1AF57B78E3491A9865942321800A203C05ED1FEEB5A28E584E19F6535E7F84E4A24F84A72DCAF5648B4A4235DD664464482F03176E888C28BFC6C1CB238CFFA35A321E71791D9EA8ED0878C61121BF8D2A4AB2C1A5E120BC40ABB1892D1715090A0EE48252CA297A99AA0E510CF26B1ADD06CA543E1C5D6BDCD3B9C585C8538045DB5C252EC3C8C3C954D9BE5907094A894E60EAB43538CFEE82E8FFC0791B0D0F43AC1627830A61D56DAD96C62958B0DE780B78BD47A604550DAB83FFF227C324049471F35248CFB849B25724FF704D5277AA352D550958BE3B237DFF473EC2ADBAEA48CA2658AEFCC77BBD4264AB374D70EAE5B964416CE8226A7E3255A0F8D7E2ADCA062BCD6D78D60D1B32E11405BE54B66EF0FDDD567702A3BCCFEDE3C584701269ED14809F06F8968356BB9267FE86E514252E88BB5C30A7ECB3D0E621021EE0FBF7871B09342BF84F55C97EAF86C48189C7FF4DF389F077E2806E5FA73B3E9458A16C7E275F4F602275580EB7B7135FB537FA0CD95D6EA58C108CD8943D70C1643111F4F01CA8A8276A902666ED81B78D168B006F16AAA3D8E4CE4F4D0FB0997E41AEFFB5B3DAA838732F357349447F387776C793C0479DE9E99498CC356FDB0075A703F23C55D47B550EC89B02ADE89329086A50843456FEDC3788AC8D97233C54560467EE1D0F024B18428F0D73B30E19F5C63B9ABF11415BEA4D0170130BAABD33C05E6524E5FB5581B22B0433342248266D0F1053B245CC2462DC44D34965102482A8ED9E4E964D5683E5D45D0C8269") - ss, err := kyberDecapsulate(dk, ct) - if err != nil { - t.Fatal(err) - } - exp, _ := hex.DecodeString("914CB67FE5C38E73BF74181C0AC50428DEDF7750A98058F7D536708774535B29") - if !bytes.Equal(ss, exp) { - t.Fatalf("got %x, want %x", ss, exp) - } -} - func TestKyberEncapsulate(t *testing.T) { dk, err := mlkem768.GenerateKey() if err != nil { From 3e14e25cf027033737aba13cd199e0df38ca5704 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 16 Oct 2024 14:31:44 +0200 Subject: [PATCH 13/34] crypto/internal/mlkem768: make Decapsulate a method This will make it easier to support multiple sizes if needed. Change-Id: I47495559fdbbf678fd98421ad6cb28172e5c810d Reviewed-on: https://go-review.googlesource.com/c/go/+/621977 Reviewed-by: Daniel McCarney Reviewed-by: Russ Cox LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Roland Shoemaker --- key_schedule.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key_schedule.go b/key_schedule.go index 9c76ebe..e8ee9ce 100644 --- a/key_schedule.go +++ b/key_schedule.go @@ -59,7 +59,7 @@ type keySharePrivateKeys struct { // kyberDecapsulate implements decapsulation according to Kyber Round 3. func kyberDecapsulate(dk *mlkem768.DecapsulationKey, c []byte) ([]byte, error) { - K, err := mlkem768.Decapsulate(dk, c) + K, err := dk.Decapsulate(c) if err != nil { return nil, err } From 5a893857d7a1e336e419be125bae8e43f6acb68e Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 21 Oct 2024 14:30:46 +0200 Subject: [PATCH 14/34] crypto/internal/mlkem768: add EncapsulationKey type Change-Id: I3feacb044caa15ac9bbfc11f5d90bebf8a505510 Reviewed-on: https://go-review.googlesource.com/c/go/+/621980 Auto-Submit: Filippo Valsorda Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Daniel McCarney Reviewed-by: Russ Cox --- handshake_client.go | 4 ++-- key_schedule.go | 9 +++++---- key_schedule_test.go | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/handshake_client.go b/handshake_client.go index f6bccc4..8965ad6 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -164,7 +164,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon if _, err := io.ReadFull(config.rand(), seed); err != nil { return nil, nil, nil, err } - keyShareKeys.kyber, err = mlkem768.NewKeyFromSeed(seed) + keyShareKeys.kyber, err = mlkem768.NewDecapsulationKey(seed) if err != nil { return nil, nil, nil, err } @@ -174,7 +174,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon // both, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2. hello.keyShares = []keyShare{ {group: x25519Kyber768Draft00, data: append(keyShareKeys.ecdhe.PublicKey().Bytes(), - keyShareKeys.kyber.EncapsulationKey()...)}, + keyShareKeys.kyber.EncapsulationKey().Bytes()...)}, {group: X25519, data: keyShareKeys.ecdhe.PublicKey().Bytes()}, } } else { diff --git a/key_schedule.go b/key_schedule.go index e8ee9ce..3bbfc1b 100644 --- a/key_schedule.go +++ b/key_schedule.go @@ -63,19 +63,20 @@ func kyberDecapsulate(dk *mlkem768.DecapsulationKey, c []byte) ([]byte, error) { if err != nil { return nil, err } - return kyberSharedSecret(K, c), nil + return kyberSharedSecret(c, K), nil } // kyberEncapsulate implements encapsulation according to Kyber Round 3. func kyberEncapsulate(ek []byte) (c, ss []byte, err error) { - c, ss, err = mlkem768.Encapsulate(ek) + k, err := mlkem768.NewEncapsulationKey(ek) if err != nil { return nil, nil, err } - return c, kyberSharedSecret(ss, c), nil + c, ss = k.Encapsulate() + return c, kyberSharedSecret(c, ss), nil } -func kyberSharedSecret(K, c []byte) []byte { +func kyberSharedSecret(c, K []byte) []byte { // Package mlkem768 implements ML-KEM, which compared to Kyber removed a // final hashing step. Compute SHAKE-256(K || SHA3-256(c), 32) to match Kyber. // See https://words.filippo.io/mlkem768/#bonus-track-using-a-ml-kem-implementation-as-kyber-v3. diff --git a/key_schedule_test.go b/key_schedule_test.go index 095113c..3253277 100644 --- a/key_schedule_test.go +++ b/key_schedule_test.go @@ -124,7 +124,7 @@ func TestKyberEncapsulate(t *testing.T) { if err != nil { t.Fatal(err) } - ct, ss, err := kyberEncapsulate(dk.EncapsulationKey()) + ct, ss, err := kyberEncapsulate(dk.EncapsulationKey().Bytes()) if err != nil { t.Fatal(err) } From d1f74ada568a50ea87373168c7f99606ed472768 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 21 Oct 2024 16:29:23 +0200 Subject: [PATCH 15/34] crypto/internal/mlkem768: add -768 suffix to all exported identifiers In preparation for introducing ML-KEM-1024. Aside from the constants at the top, all other changes were automated. Change-Id: I0fafce9a776c7b0b9179be1c858709cabf60e80f Reviewed-on: https://go-review.googlesource.com/c/go/+/621981 Auto-Submit: Filippo Valsorda Reviewed-by: Roland Shoemaker Reviewed-by: Russ Cox Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI --- handshake_client.go | 2 +- handshake_client_tls13.go | 2 +- handshake_server_tls13.go | 2 +- key_schedule.go | 6 +++--- key_schedule_test.go | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/handshake_client.go b/handshake_client.go index 8965ad6..1c14476 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -164,7 +164,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon if _, err := io.ReadFull(config.rand(), seed); err != nil { return nil, nil, nil, err } - keyShareKeys.kyber, err = mlkem768.NewDecapsulationKey(seed) + keyShareKeys.kyber, err = mlkem768.NewDecapsulationKey768(seed) if err != nil { return nil, nil, nil, err } diff --git a/handshake_client_tls13.go b/handshake_client_tls13.go index cdef806..fbec743 100644 --- a/handshake_client_tls13.go +++ b/handshake_client_tls13.go @@ -481,7 +481,7 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { ecdhePeerData := hs.serverHello.serverShare.data if hs.serverHello.serverShare.group == x25519Kyber768Draft00 { - if len(ecdhePeerData) != x25519PublicKeySize+mlkem768.CiphertextSize { + if len(ecdhePeerData) != x25519PublicKeySize+mlkem768.CiphertextSize768 { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid server key share") } diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index 29add50..3591aa1 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -223,7 +223,7 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { ecdhData := clientKeyShare.data if selectedGroup == x25519Kyber768Draft00 { ecdhGroup = X25519 - if len(ecdhData) != x25519PublicKeySize+mlkem768.EncapsulationKeySize { + if len(ecdhData) != x25519PublicKeySize+mlkem768.EncapsulationKeySize768 { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid Kyber client key share") } diff --git a/key_schedule.go b/key_schedule.go index 3bbfc1b..8377807 100644 --- a/key_schedule.go +++ b/key_schedule.go @@ -54,11 +54,11 @@ func (c *cipherSuiteTLS13) exportKeyingMaterial(s *tls13.MasterSecret, transcrip type keySharePrivateKeys struct { curveID CurveID ecdhe *ecdh.PrivateKey - kyber *mlkem768.DecapsulationKey + kyber *mlkem768.DecapsulationKey768 } // kyberDecapsulate implements decapsulation according to Kyber Round 3. -func kyberDecapsulate(dk *mlkem768.DecapsulationKey, c []byte) ([]byte, error) { +func kyberDecapsulate(dk *mlkem768.DecapsulationKey768, c []byte) ([]byte, error) { K, err := dk.Decapsulate(c) if err != nil { return nil, err @@ -68,7 +68,7 @@ func kyberDecapsulate(dk *mlkem768.DecapsulationKey, c []byte) ([]byte, error) { // kyberEncapsulate implements encapsulation according to Kyber Round 3. func kyberEncapsulate(ek []byte) (c, ss []byte, err error) { - k, err := mlkem768.NewEncapsulationKey(ek) + k, err := mlkem768.NewEncapsulationKey768(ek) if err != nil { return nil, nil, err } diff --git a/key_schedule_test.go b/key_schedule_test.go index 3253277..766370f 100644 --- a/key_schedule_test.go +++ b/key_schedule_test.go @@ -120,7 +120,7 @@ func TestTrafficKey(t *testing.T) { } func TestKyberEncapsulate(t *testing.T) { - dk, err := mlkem768.GenerateKey() + dk, err := mlkem768.GenerateKey768() if err != nil { t.Fatal(err) } From 0eeabaa9d73193b622b45e8c7e4a40c53b27141b Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 23 Oct 2024 11:41:42 +0200 Subject: [PATCH 16/34] crypto/internal/mlkem768: move to crypto/internal/fips/mlkem In the process, replace out-of-module imports with their FIPS versions. For #69536 Change-Id: I83e900b7c38ecf760382e5dca7fd0b1eaa5a5589 Reviewed-on: https://go-review.googlesource.com/c/go/+/626879 LUCI-TryBot-Result: Go LUCI Reviewed-by: Russ Cox Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney Reviewed-by: Michael Knyszek --- handshake_client.go | 6 +++--- handshake_client_tls13.go | 4 ++-- handshake_server_tls13.go | 4 ++-- key_schedule.go | 18 +++++++++--------- key_schedule_test.go | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/handshake_client.go b/handshake_client.go index 1c14476..ea9c4c5 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -10,9 +10,9 @@ import ( "crypto" "crypto/ecdsa" "crypto/ed25519" + "crypto/internal/fips/mlkem" "crypto/internal/fips/tls13" "crypto/internal/hpke" - "crypto/internal/mlkem768" "crypto/rsa" "crypto/subtle" "crypto/x509" @@ -160,11 +160,11 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon if err != nil { return nil, nil, nil, err } - seed := make([]byte, mlkem768.SeedSize) + seed := make([]byte, mlkem.SeedSize) if _, err := io.ReadFull(config.rand(), seed); err != nil { return nil, nil, nil, err } - keyShareKeys.kyber, err = mlkem768.NewDecapsulationKey768(seed) + keyShareKeys.kyber, err = mlkem.NewDecapsulationKey768(seed) if err != nil { return nil, nil, nil, err } diff --git a/handshake_client_tls13.go b/handshake_client_tls13.go index fbec743..6ce83b9 100644 --- a/handshake_client_tls13.go +++ b/handshake_client_tls13.go @@ -10,8 +10,8 @@ import ( "crypto" "crypto/hmac" "crypto/internal/fips/hkdf" + "crypto/internal/fips/mlkem" "crypto/internal/fips/tls13" - "crypto/internal/mlkem768" "crypto/rsa" "crypto/subtle" "errors" @@ -481,7 +481,7 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { ecdhePeerData := hs.serverHello.serverShare.data if hs.serverHello.serverShare.group == x25519Kyber768Draft00 { - if len(ecdhePeerData) != x25519PublicKeySize+mlkem768.CiphertextSize768 { + if len(ecdhePeerData) != x25519PublicKeySize+mlkem.CiphertextSize768 { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid server key share") } diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index 3591aa1..aa1ffd9 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -9,8 +9,8 @@ import ( "context" "crypto" "crypto/hmac" + "crypto/internal/fips/mlkem" "crypto/internal/fips/tls13" - "crypto/internal/mlkem768" "crypto/rsa" "errors" "hash" @@ -223,7 +223,7 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { ecdhData := clientKeyShare.data if selectedGroup == x25519Kyber768Draft00 { ecdhGroup = X25519 - if len(ecdhData) != x25519PublicKeySize+mlkem768.EncapsulationKeySize768 { + if len(ecdhData) != x25519PublicKeySize+mlkem.EncapsulationKeySize768 { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid Kyber client key share") } diff --git a/key_schedule.go b/key_schedule.go index 8377807..99229ea 100644 --- a/key_schedule.go +++ b/key_schedule.go @@ -7,13 +7,12 @@ package tls import ( "crypto/ecdh" "crypto/hmac" + "crypto/internal/fips/mlkem" + "crypto/internal/fips/sha3" "crypto/internal/fips/tls13" - "crypto/internal/mlkem768" "errors" "hash" "io" - - "golang.org/x/crypto/sha3" ) // This file contains the functions necessary to compute the TLS 1.3 key @@ -54,11 +53,11 @@ func (c *cipherSuiteTLS13) exportKeyingMaterial(s *tls13.MasterSecret, transcrip type keySharePrivateKeys struct { curveID CurveID ecdhe *ecdh.PrivateKey - kyber *mlkem768.DecapsulationKey768 + kyber *mlkem.DecapsulationKey768 } // kyberDecapsulate implements decapsulation according to Kyber Round 3. -func kyberDecapsulate(dk *mlkem768.DecapsulationKey768, c []byte) ([]byte, error) { +func kyberDecapsulate(dk *mlkem.DecapsulationKey768, c []byte) ([]byte, error) { K, err := dk.Decapsulate(c) if err != nil { return nil, err @@ -68,7 +67,7 @@ func kyberDecapsulate(dk *mlkem768.DecapsulationKey768, c []byte) ([]byte, error // kyberEncapsulate implements encapsulation according to Kyber Round 3. func kyberEncapsulate(ek []byte) (c, ss []byte, err error) { - k, err := mlkem768.NewEncapsulationKey768(ek) + k, err := mlkem.NewEncapsulationKey768(ek) if err != nil { return nil, nil, err } @@ -77,13 +76,14 @@ func kyberEncapsulate(ek []byte) (c, ss []byte, err error) { } func kyberSharedSecret(c, K []byte) []byte { - // Package mlkem768 implements ML-KEM, which compared to Kyber removed a + // Package mlkem implements ML-KEM, which compared to Kyber removed a // final hashing step. Compute SHAKE-256(K || SHA3-256(c), 32) to match Kyber. // See https://words.filippo.io/mlkem768/#bonus-track-using-a-ml-kem-implementation-as-kyber-v3. h := sha3.NewShake256() h.Write(K) - ch := sha3.Sum256(c) - h.Write(ch[:]) + ch := sha3.New256() + ch.Write(c) + h.Write(ch.Sum(nil)) out := make([]byte, 32) h.Read(out) return out diff --git a/key_schedule_test.go b/key_schedule_test.go index 766370f..0dc3601 100644 --- a/key_schedule_test.go +++ b/key_schedule_test.go @@ -6,8 +6,8 @@ package tls import ( "bytes" + "crypto/internal/fips/mlkem" "crypto/internal/fips/tls13" - "crypto/internal/mlkem768" "crypto/sha256" "encoding/hex" "strings" @@ -120,7 +120,7 @@ func TestTrafficKey(t *testing.T) { } func TestKyberEncapsulate(t *testing.T) { - dk, err := mlkem768.GenerateKey768() + dk, err := mlkem.GenerateKey768() if err != nil { t.Fatal(err) } From 548fd92733dc5b253590e2386bf48e3cd452d419 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sat, 16 Nov 2024 23:45:05 +0100 Subject: [PATCH 17/34] crypto/ecdsa: implement deterministic and hedged signatures For the future, some test vectors we should generate and then share through Wycheproof or CCTV: - A private key with a leading zero byte. - A hash longer than the modulus. - A hash longer than the P-521 modulus by a few bits. - Reductions happening in hashToNat and bits2octets. Fixes #64802 Change-Id: Ia0f89781b2c78eedd5103cf0e9720630711c37ad Reviewed-on: https://go-review.googlesource.com/c/go/+/628681 TryBot-Bypass: Filippo Valsorda Reviewed-by: Russ Cox Reviewed-by: Dmitri Shuralyov Auto-Submit: Filippo Valsorda --- testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA | 80 +++--- testdata/Client-TLSv10-ClientCert-ECDSA-RSA | 80 +++--- testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA | 96 +++---- testdata/Client-TLSv12-ClientCert-ECDSA-RSA | 78 +++--- testdata/Client-TLSv13-ClientCert-ECDSA-RSA | 236 +++++++++--------- testdata/Server-TLSv10-ECDHE-ECDSA-AES | 66 ++--- testdata/Server-TLSv12-ECDHE-ECDSA-AES | 64 ++--- testdata/Server-TLSv13-ECDHE-ECDSA-AES | 158 ++++++------ 8 files changed, 429 insertions(+), 429 deletions(-) diff --git a/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA index a35aa57..b79aec6 100644 --- a/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA +++ b/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA @@ -17,11 +17,11 @@ 000000f0 bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 |.).0.........._X| 00000100 cb 3b 74 |.;t| >>> Flow 2 (server to client) -00000000 16 03 01 00 5d 02 00 00 59 03 01 60 8a bf 2b 6f |....]...Y..`..+o| -00000010 c1 f0 f3 7b d4 78 2c d9 15 3f 33 6a 4b 96 aa 83 |...{.x,..?3jK...| -00000020 54 ae 66 8f 0f e7 b1 68 31 00 39 20 d8 4d f2 2c |T.f....h1.9 .M.,| -00000030 8b 85 98 d6 af e0 07 98 d5 cb 89 72 fb 8d c0 73 |...........r...s| -00000040 cc 68 cf 58 21 4a 8a fc c3 8e 90 0a c0 09 00 00 |.h.X!J..........| +00000000 16 03 01 00 5d 02 00 00 59 03 01 58 ee cb 2c 2e |....]...Y..X..,.| +00000010 24 e7 e4 50 2b 4b 9c 0f ab f5 79 c1 12 b6 89 e5 |$..P+K....y.....| +00000020 83 41 06 cb 45 f6 66 e9 e1 d2 fe 20 95 fd 7f 15 |.A..E.f.... ....| +00000030 44 4e 44 18 9b fc 16 a7 8a a4 d9 f7 ca 49 85 e8 |DND..........I..| +00000040 00 ce 02 26 38 38 1b 8d 6d 16 f2 b8 c0 09 00 00 |...&88..m.......| 00000050 11 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 17 |................| 00000060 00 00 16 03 01 02 0e 0b 00 02 0a 00 02 07 00 02 |................| 00000070 04 30 82 02 00 30 82 01 62 02 09 00 b8 bf 2d 47 |.0...0..b.....-G| @@ -57,17 +57,17 @@ 00000250 c9 86 2e dd d7 11 69 7f 85 7c 56 de fb 31 78 2b |......i..|V..1x+| 00000260 e4 c7 78 0d ae cb be 9e 4e 36 24 31 7b 6a 0f 39 |..x.....N6$1{j.9| 00000270 95 12 07 8f 2a 16 03 01 00 b5 0c 00 00 b1 03 00 |....*...........| -00000280 1d 20 68 5a 6f c6 20 26 b5 5c 47 c6 5e fb 23 c4 |. hZo. &.\G.^.#.| -00000290 bc 9c 3f 3a 9b ed d6 8e a3 c8 66 7d 9b cb d0 30 |..?:......f}...0| -000002a0 f9 60 00 8b 30 81 88 02 42 01 b2 fb f8 5f d0 14 |.`..0...B...._..| -000002b0 9d 3c 55 0f 16 50 6f d5 0c 4c 3e 73 2e a9 23 5f |.s..#_| -000002c0 e8 9c 02 5d 4c 6d b0 c1 9e 0d ac 59 36 6c d5 c2 |...]Lm.....Y6l..| -000002d0 4c 94 94 94 6f a4 df 26 1a 54 f5 74 b8 49 75 49 |L...o..&.T.t.IuI| -000002e0 9c aa cd 91 24 f3 52 88 6a 1e 80 02 42 01 81 a2 |....$.R.j...B...| -000002f0 76 e2 e8 b0 2a 8e 4e ed 6d be 2f e3 ca 4c ff f2 |v...*.N.m./..L..| -00000300 d3 14 c0 b5 f8 c5 53 04 97 de 14 b2 8e af 77 86 |......S.......w.| -00000310 de bf 4a 59 cf 7b 8a 73 d3 95 c3 28 ca 25 63 8e |..JY.{.s...(.%c.| -00000320 9e 02 7f 8a 04 bb 69 1e 41 31 76 2b 5a 54 ed 16 |......i.A1v+ZT..| +00000280 1d 20 b2 d4 b5 f1 3f 61 7d 07 30 8b fd 17 76 41 |. ....?a}.0...vA| +00000290 12 c5 e1 25 f1 e9 ad 68 26 55 4b f5 60 16 b0 44 |...%...h&UK.`..D| +000002a0 90 7a 00 8b 30 81 88 02 42 01 26 8b c1 0d 38 f2 |.z..0...B.&...8.| +000002b0 0f 22 de fd 81 53 5b 5a 87 b6 57 23 33 22 06 8f |."...S[Z..W#3"..| +000002c0 8b 59 f1 70 85 46 41 f2 b7 0c 80 77 df 40 08 77 |.Y.p.FA....w.@.w| +000002d0 e1 b8 21 7f 55 77 c7 b7 ef ef b5 31 ae a0 22 a8 |..!.Uw.....1..".| +000002e0 d3 e0 67 e8 67 bc a9 cb 03 47 76 02 42 00 f4 7a |..g.g....Gv.B..z| +000002f0 eb 2f d0 82 d7 06 75 35 e4 61 fb cf 27 93 95 29 |./....u5.a..'..)| +00000300 6e 2c b5 d4 01 45 5b b6 d9 72 e9 f9 13 a6 5f bd |n,...E[..r...._.| +00000310 24 76 3b 8e 48 7a ce 4f f5 c2 77 75 66 2d 18 6d |$v;.Hz.O..wuf-.m| +00000320 7d 9e c7 95 0c fe 0b 80 15 67 b2 f2 f6 5a dd 16 |}........g...Z..| 00000330 03 01 00 0a 0d 00 00 06 03 01 02 40 00 00 16 03 |...........@....| 00000340 01 00 04 0e 00 00 00 |.......| >>> Flow 3 (client to server) @@ -107,29 +107,29 @@ 00000210 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b| 00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......| 00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 91 0f 00 |...._X.;t.......| -00000240 00 8d 00 8b 30 81 88 02 42 01 57 eb e6 90 3c fe |....0...B.W...<.| -00000250 10 8d e9 7d 50 a5 d3 83 43 64 e7 d0 cb 65 ef b9 |...}P...Cd...e..| -00000260 56 59 b9 52 09 e8 52 d7 d7 4d a7 57 09 dd 1f 83 |VY.R..R..M.W....| -00000270 22 0e 4c 4e 8b 50 0d 68 72 26 9e 2a 8b 6d cb 88 |".LN.P.hr&.*.m..| -00000280 c8 f4 0d 7d 85 80 e2 ec 7f f1 be 02 42 01 68 5d |...}........B.h]| -00000290 f8 91 45 82 61 7f 57 e2 2e b2 54 7d f3 11 11 44 |..E.a.W...T}...D| -000002a0 2f ee 48 91 17 5c 04 3d b8 0e eb ed 66 33 b1 62 |/.H..\.=....f3.b| -000002b0 61 a1 03 e8 77 cf 44 4b 93 fc 4f 12 24 2f d1 67 |a...w.DK..O.$/.g| -000002c0 c8 4b 07 e3 cb a8 7d 5d 82 d4 a2 ec d7 0b f8 14 |.K....}]........| -000002d0 03 01 00 01 01 16 03 01 00 30 28 45 dc 18 db 52 |.........0(E...R| -000002e0 a7 b5 1e 68 7a 06 03 8a 23 87 07 ea 79 38 29 ec |...hz...#...y8).| -000002f0 1b b7 b9 cb 1b 04 ac ba 1d b2 d5 8e 71 e0 27 30 |............q.'0| -00000300 02 d1 c9 4d 35 69 38 71 c9 c7 |...M5i8q..| +00000240 00 8d 00 8b 30 81 88 02 42 01 87 b2 c8 53 94 c3 |....0...B....S..| +00000250 9f ea 8a 04 35 1e 53 fb c0 db c5 43 e8 99 b7 81 |....5.S....C....| +00000260 43 fd 47 fd a6 cd 89 b5 0a b9 d0 5d 79 b0 c2 1a |C.G........]y...| +00000270 94 1f d8 2e 2b 8d 23 2a c8 08 63 98 f6 01 1f 8f |....+.#*..c.....| +00000280 67 60 3a 88 44 63 7e 8b 91 3e 48 02 42 00 e1 1f |g`:.Dc~..>H.B...| +00000290 69 9a 97 bb b6 e9 97 4d f5 f5 d7 23 56 be 1d ff |i......M...#V...| +000002a0 f0 22 67 8d a3 a1 13 33 5b f7 0b c2 a3 c8 5a 8c |."g....3[.....Z.| +000002b0 e8 65 b8 a8 7e 6c 99 11 db ab bd 80 0a ca dd 5a |.e..~l.........Z| +000002c0 d4 e0 28 12 38 7a b4 86 e7 3e 13 05 a1 3f 5f 14 |..(.8z...>...?_.| +000002d0 03 01 00 01 01 16 03 01 00 30 9a fa ce 11 0b 50 |.........0.....P| +000002e0 fa a1 59 9b 89 41 a9 0b 1b 74 dd 8f 7b a9 e0 39 |..Y..A...t..{..9| +000002f0 5d e3 cc ee 11 f4 27 15 bc 4c 8f e1 2c 51 ec 8e |].....'..L..,Q..| +00000300 ed 6c 97 75 4c e9 da fb 68 9d |.l.uL...h.| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 3d a8 df 2e 80 |..........0=....| -00000010 26 22 66 32 fb 6e bc 9e f5 d6 6a 5e 0a 18 34 92 |&"f2.n....j^..4.| -00000020 f9 42 40 e4 9c b1 7a 28 d2 52 e9 b8 13 ce 89 01 |.B@...z(.R......| -00000030 23 44 ab 2e 75 3e c2 96 f5 59 61 |#D..u>...Ya| +00000000 14 03 01 00 01 01 16 03 01 00 30 12 06 0c 4d 1c |..........0...M.| +00000010 81 47 06 5f b9 85 68 60 9c 26 4a 14 f2 40 60 7f |.G._..h`.&J..@`.| +00000020 d1 1e 51 9e f2 70 2f be 54 cb 42 b3 b3 8d 90 9c |..Q..p/.T.B.....| +00000030 9d d2 0d e2 f7 b6 56 31 11 af 5f |......V1.._| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 64 ac d2 1b 98 4d 4e ec 22 25 35 |.... d....MN."%5| -00000010 7c 7c 79 15 a8 54 0d 93 1a b3 3e ff 68 27 d0 d5 |||y..T....>.h'..| -00000020 82 24 7b dc e7 17 03 01 00 20 98 da 6d 26 de b8 |.${...... ..m&..| -00000030 4b d0 ee 2c 18 52 05 86 59 b0 b6 e7 42 74 54 ea |K..,.R..Y...BtT.| -00000040 e6 96 de ec 82 dc 1f 3a 6c 5c 15 03 01 00 20 cc |.......:l\.... .| -00000050 11 da e4 75 e5 0c 06 84 e5 89 3e a4 ef 3c 28 10 |...u......>..<(.| -00000060 68 0a 6f d4 6e ae 14 a6 ca 7c ba 98 c4 28 7e |h.o.n....|...(~| +00000000 17 03 01 00 20 0f d0 65 cd d4 59 d0 9e 07 06 6d |.... ..e..Y....m| +00000010 8a 11 34 d9 3a 31 59 70 02 39 08 ef 28 98 36 2f |..4.:1Yp.9..(.6/| +00000020 0d 5b d0 23 3f 17 03 01 00 20 5b 16 82 9c 29 c6 |.[.#?.... [...).| +00000030 78 34 76 09 5e bb 01 5e fc 01 b2 55 9b ef 67 a8 |x4v.^..^...U..g.| +00000040 ca 9f b9 6d b5 ea 87 48 8e 76 15 03 01 00 20 43 |...m...H.v.... C| +00000050 12 3b f6 99 31 67 d8 8a 94 d1 37 ef 01 ca a1 62 |.;..1g....7....b| +00000060 9f d7 2a eb 7e 37 79 d9 a4 07 15 5f fb 84 32 |..*.~7y...._..2| diff --git a/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/testdata/Client-TLSv10-ClientCert-ECDSA-RSA index 687eba4..b02fe3d 100644 --- a/testdata/Client-TLSv10-ClientCert-ECDSA-RSA +++ b/testdata/Client-TLSv10-ClientCert-ECDSA-RSA @@ -17,11 +17,11 @@ 000000f0 bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 |.).0.........._X| 00000100 cb 3b 74 |.;t| >>> Flow 2 (server to client) -00000000 16 03 01 00 5d 02 00 00 59 03 01 48 c6 a1 aa 01 |....]...Y..H....| -00000010 b8 4b a1 f5 6d 71 28 f7 fd 76 9d 12 50 d3 56 e2 |.K..mq(..v..P.V.| -00000020 ca 77 d4 82 07 65 e2 c5 12 40 35 20 e3 ee 0a df |.w...e...@5 ....| -00000030 1f 4a d9 b3 a6 6f a0 24 49 8d ab d9 d8 3c 24 36 |.J...o.$I....<$6| -00000040 35 ba 64 8b 7d ec 29 91 d9 26 5e 61 c0 13 00 00 |5.d.}.)..&^a....| +00000000 16 03 01 00 5d 02 00 00 59 03 01 0b 4b bc a9 e8 |....]...Y...K...| +00000010 4a 08 69 de 73 f8 fc 53 c6 e9 cd cf 25 7a 5f b6 |J.i.s..S....%z_.| +00000020 60 48 65 3e f5 5f 9f 14 e7 38 a0 20 ec fe 94 b2 |`He>._...8. ....| +00000030 6d a9 d7 91 c4 92 6b 3e a4 2e 88 72 07 c3 47 12 |m.....k>...r..G.| +00000040 78 cc 45 86 f9 56 16 f9 d7 d9 38 c2 c0 13 00 00 |x.E..V....8.....| 00000050 11 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 17 |................| 00000060 00 00 16 03 01 02 59 0b 00 02 55 00 02 52 00 02 |......Y...U..R..| 00000070 4f 30 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 |O0..K0..........| @@ -61,17 +61,17 @@ 00000290 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 |s..Cw.......@.a.| 000002a0 4c 72 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 |Lr+...F..M...>..| 000002b0 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 |.B...=.`.\!.;...| -000002c0 16 03 01 00 aa 0c 00 00 a6 03 00 1d 20 55 51 65 |............ UQe| -000002d0 bb 06 22 d7 d6 97 39 d1 f4 dc 95 06 b3 a4 a7 00 |.."...9.........| -000002e0 d1 e5 98 bc 97 12 03 25 03 12 ab 20 4f 00 80 71 |.......%... O..q| -000002f0 8d 3c 54 44 ba df 73 92 76 16 d1 ec b1 de a2 27 |.>> Flow 3 (client to server) @@ -111,29 +111,29 @@ 00000210 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b| 00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......| 00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 90 0f 00 |...._X.;t.......| -00000240 00 8c 00 8a 30 81 87 02 41 79 c5 57 74 46 9a 18 |....0...Ay.WtF..| -00000250 ad e0 b0 ba 68 f5 0e e2 58 94 dc 73 84 5a f8 86 |....h...X..s.Z..| -00000260 86 8e 2a 37 82 02 a1 4b 19 cd 71 b3 99 04 64 b0 |..*7...K..q...d.| -00000270 db 4a cc 41 a6 17 28 38 f1 67 bd 59 16 97 71 32 |.J.A..(8.g.Y..q2| -00000280 06 71 24 2c f3 df 34 1b a3 b8 02 42 01 2f 2f db |.q$,..4....B.//.| -00000290 45 07 94 53 89 81 59 0b 92 9d 1a 05 42 b3 1c 40 |E..S..Y.....B..@| -000002a0 38 50 a1 8e a6 35 15 76 ca 75 7e fc 8d 7b 36 f3 |8P...5.v.u~..{6.| -000002b0 e3 e7 bf f9 bd 94 35 a0 c5 2b 35 88 be 5d ee f1 |......5..+5..]..| -000002c0 00 f9 9c a8 01 a8 92 5d d6 17 b6 54 98 e4 14 03 |.......]...T....| -000002d0 01 00 01 01 16 03 01 00 30 1f d6 11 ac 58 b3 20 |........0....X. | -000002e0 31 6d 3b f5 83 98 50 75 ff 4f 79 61 2b fc 0f 6c |1m;...Pu.Oya+..l| -000002f0 a6 4d 9e 65 38 e3 ca 12 76 0a 56 1e dd 73 da e1 |.M.e8...v.V..s..| -00000300 66 5a 33 62 8f 7d c3 ed ad |fZ3b.}...| +00000240 00 8c 00 8a 30 81 87 02 41 2c f8 d2 c2 28 75 28 |....0...A,...(u(| +00000250 67 de 75 fb 7a 09 20 8a ec 06 a6 42 03 ad 3c 95 |g.u.z. ....B..<.| +00000260 bb 00 f6 10 71 c7 90 fe 08 16 fa ed 7d 71 24 a2 |....q.......}q$.| +00000270 b6 76 ce f9 1b ff a9 ff 05 b6 dd d8 63 2b 74 86 |.v..........c+t.| +00000280 65 f5 ef f7 36 41 47 77 b5 88 02 42 00 8a 80 f8 |e...6AGw...B....| +00000290 9b cf de a6 b7 c3 d8 48 a1 a0 47 7e cf 33 fc f7 |.......H..G~.3..| +000002a0 fc 87 40 cf 8d c3 81 85 c7 19 9e 37 9e 54 f7 3e |..@........7.T.>| +000002b0 d1 1c 42 83 21 d7 2e ae 02 7b 3c ce 97 f3 9b a0 |..B.!....{<.....| +000002c0 a3 4e b9 a0 9c 78 f0 7e 9c 96 fc 78 e6 08 14 03 |.N...x.~...x....| +000002d0 01 00 01 01 16 03 01 00 30 84 a0 4f 8d 01 40 ca |........0..O..@.| +000002e0 c0 fd ea 1a 9c df 27 cc 25 00 56 e2 30 05 c0 d9 |......'.%.V.0...| +000002f0 c7 21 48 37 6b 35 c3 a4 4e bf 67 98 87 78 0f 3c |.!H7k5..N.g..x.<| +00000300 74 72 4f 6a c5 0d fd 0c 84 |trOj.....| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 92 36 25 46 a5 |..........0.6%F.| -00000010 44 e6 31 25 cd 24 15 df 13 f8 5b a3 af 7c 12 43 |D.1%.$....[..|.C| -00000020 b8 8c 39 84 bc 25 06 02 02 86 78 20 1b ec 98 1a |..9..%....x ....| -00000030 31 b3 b8 cf 82 92 77 ff 08 87 fb |1.....w....| +00000000 14 03 01 00 01 01 16 03 01 00 30 01 da 6e 2a 83 |..........0..n*.| +00000010 20 ad 52 16 f2 c6 c1 55 b8 77 0d 5f c6 48 dc e7 | .R....U.w._.H..| +00000020 72 29 88 0a 2b 1a d1 1e fd fb c0 c3 18 c8 43 47 |r)..+.........CG| +00000030 a9 8f d3 fe f3 d8 d2 a8 ce 79 44 |.........yD| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 2f bd ab e0 2f 9a 81 58 99 35 bb |.... /.../..X.5.| -00000010 86 61 6e 15 be 31 d7 ad 44 1d d9 cf 2f fc d9 f6 |.an..1..D.../...| -00000020 da b6 48 32 27 17 03 01 00 20 76 70 b7 7d 1b 05 |..H2'.... vp.}..| -00000030 ee 54 99 bf 89 79 79 b5 68 c1 84 3c 6d 47 5c d1 |.T...yy.h..>> Flow 2 (server to client) -00000000 16 03 03 00 5d 02 00 00 59 03 03 d4 19 2c 08 c6 |....]...Y....,..| -00000010 ef 32 88 79 a1 84 fc 79 38 62 b2 dd 4b a7 0b b3 |.2.y...y8b..K...| -00000020 d3 13 3d d4 f7 c7 4d d9 8b c6 8e 20 56 8e 90 3d |..=...M.... V..=| -00000030 2b 6e 2d cf 7e c1 c6 b0 e5 d8 d2 af 3a 06 88 c6 |+n-.~.......:...| -00000040 ed e7 18 76 ab 45 c5 76 47 67 95 ad c0 09 00 00 |...v.E.vGg......| +00000000 16 03 03 00 5d 02 00 00 59 03 03 58 a7 ae 6c fc |....]...Y..X..l.| +00000010 0d 53 51 d5 37 8d 1f 88 75 27 bf 34 8f 3d d3 ee |.SQ.7...u'.4.=..| +00000020 95 db 77 d9 c0 3b f1 57 4f 84 e2 20 7f 0d d1 84 |..w..;.WO.. ....| +00000030 0c 7a 4e 41 7f 74 58 6c f5 38 e6 8d 5b 04 15 e1 |.zNA.tXl.8..[...| +00000040 3d 4a ba 7e 58 f4 e8 bf f4 42 8a f5 c0 09 00 00 |=J.~X....B......| 00000050 11 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 17 |................| 00000060 00 00 16 03 03 02 0e 0b 00 02 0a 00 02 07 00 02 |................| 00000070 04 30 82 02 00 30 82 01 62 02 09 00 b8 bf 2d 47 |.0...0..b.....-G| @@ -56,23 +56,23 @@ 00000240 8c 25 c1 33 13 83 0d 94 06 bb d4 37 7a f6 ec 7a |.%.3.......7z..z| 00000250 c9 86 2e dd d7 11 69 7f 85 7c 56 de fb 31 78 2b |......i..|V..1x+| 00000260 e4 c7 78 0d ae cb be 9e 4e 36 24 31 7b 6a 0f 39 |..x.....N6$1{j.9| -00000270 95 12 07 8f 2a 16 03 03 00 b7 0c 00 00 b3 03 00 |....*...........| -00000280 1d 20 e9 3c ed d4 07 43 c1 20 f5 41 35 e1 49 4a |. .<...C. .A5.IJ| -00000290 1c 52 5d 77 f2 07 59 18 55 e0 66 d1 49 ab 95 74 |.R]w..Y.U.f.I..t| -000002a0 81 1c 04 03 00 8b 30 81 88 02 42 01 f1 52 e7 13 |......0...B..R..| -000002b0 3e 9b 3b 4f 90 0f d2 9b 50 11 fe df 1f 12 f2 d9 |>.;O....P.......| -000002c0 0d 89 bc 6c 01 93 45 ca b8 3c 09 cf b2 01 e9 99 |...l..E..<......| -000002d0 87 fb 1d ac 91 7f 77 a2 21 5e 07 5e 65 3b ec 31 |......w.!^.^e;.1| -000002e0 d7 b5 b9 1d 88 c8 82 f5 03 a9 37 e8 b9 02 42 01 |..........7...B.| -000002f0 78 c4 90 fb e3 7f 5a 7a 66 0a 44 f5 66 0e 1e ac |x.....Zzf.D.f...| -00000300 cb 53 c4 74 55 3a b8 b7 ec b3 f6 4c e1 a8 b6 cb |.S.tU:.....L....| -00000310 a1 e5 37 ac e2 17 e2 6c 8f 71 37 b0 f1 ca b8 1b |..7....l.q7.....| -00000320 df 91 16 a4 7f 31 b1 4f 3e e4 30 f0 5a 5e df 93 |.....1.O>.0.Z^..| -00000330 85 16 03 03 00 3a 0d 00 00 36 03 01 02 40 00 2e |.....:...6...@..| -00000340 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................| -00000350 08 04 08 05 08 06 04 01 05 01 06 01 03 03 02 03 |................| -00000360 03 01 02 01 03 02 02 02 04 02 05 02 06 02 00 00 |................| -00000370 16 03 03 00 04 0e 00 00 00 |.........| +00000270 95 12 07 8f 2a 16 03 03 00 b6 0c 00 00 b2 03 00 |....*...........| +00000280 1d 20 b2 5c fe 84 12 a5 2f 8f da 91 3f 44 52 4e |. .\..../...?DRN| +00000290 03 ad e4 f9 8a 14 71 0d 0b 46 86 81 d2 1b 4a 5b |......q..F....J[| +000002a0 d9 4e 04 03 00 8a 30 81 87 02 42 01 78 d2 c2 a9 |.N....0...B.x...| +000002b0 b7 77 f8 eb 8d 9d 36 1f 79 e7 d1 74 a9 9d a4 53 |.w....6.y..t...S| +000002c0 5e 08 4a 92 dc ac b3 32 bf ce e7 f0 80 af 56 48 |^.J....2......VH| +000002d0 42 e2 fd 22 c7 35 11 13 db 2a 6d 74 4a e5 02 ce |B..".5...*mtJ...| +000002e0 ea 43 e6 b0 69 18 3e d3 86 85 76 ff 56 02 41 44 |.C..i.>...v.V.AD| +000002f0 2a e1 6b ae 5d f9 39 5c ec 76 ee 01 d7 04 42 ca |*.k.].9\.v....B.| +00000300 45 07 e0 59 38 75 d4 47 61 a4 5b 0f a9 7a ba 79 |E..Y8u.Ga.[..z.y| +00000310 fa 79 92 41 88 8a d3 be c2 38 3e f7 95 6c 99 3f |.y.A.....8>..l.?| +00000320 4c ff af 10 33 14 25 e0 d7 8a fd 70 17 2b 73 ee |L...3.%....p.+s.| +00000330 16 03 03 00 3a 0d 00 00 36 03 01 02 40 00 2e 04 |....:...6...@...| +00000340 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 |................| +00000350 04 08 05 08 06 04 01 05 01 06 01 03 03 02 03 03 |................| +00000360 01 02 01 03 02 02 02 04 02 05 02 06 02 00 00 16 |................| +00000370 03 03 00 04 0e 00 00 00 |........| >>> Flow 3 (client to server) 00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| 00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5| @@ -109,32 +109,32 @@ 00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..| 00000210 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b| 00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......| -00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 93 0f 00 |...._X.;t.......| -00000240 00 8f 04 03 00 8b 30 81 88 02 42 01 c9 2c e8 1f |......0...B..,..| -00000250 5b a0 97 0f 70 2d 46 e3 6e b4 4c 82 fc be df 05 |[...p-F.n.L.....| -00000260 09 b0 d7 e4 0a 06 71 66 d6 3b 3e b6 56 2c 22 c7 |......qf.;>.V,".| -00000270 7c 3a 63 5c 34 22 5b 3a 49 a2 97 f3 2f 58 e7 2a ||:c\4"[:I.../X.*| -00000280 cd f4 05 84 db 8b 0b 22 e3 50 1b e7 6d 02 42 01 |.......".P..m.B.| -00000290 fd 1e bc 64 8b 01 3f a0 f8 8b 41 be 4d 97 07 6c |...d..?...A.M..l| -000002a0 3b 09 74 d6 00 76 b3 a0 c0 d0 92 d0 78 24 d7 b2 |;.t..v......x$..| -000002b0 1f c0 86 90 59 3a fb a8 e1 f6 80 23 db f7 90 93 |....Y:.....#....| -000002c0 95 fd 37 14 8c 34 f3 07 10 f8 dd e3 66 28 1c b2 |..7..4......f(..| -000002d0 a0 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 |...........@....| -000002e0 00 00 00 00 00 00 00 00 00 00 00 00 6c b8 ab 0b |............l...| -000002f0 c1 2d 2f 4e d2 25 14 96 24 c6 18 97 82 93 1c 1b |.-/N.%..$.......| -00000300 b4 ca 77 8b 17 7c cf 08 ca 06 e2 ef f3 97 6a 31 |..w..|........j1| -00000310 88 aa 46 a2 d3 7b 65 56 e2 77 72 df |..F..{eV.wr.| +00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 92 0f 00 |...._X.;t.......| +00000240 00 8e 04 03 00 8a 30 81 87 02 41 0c 11 31 08 e0 |......0...A..1..| +00000250 7d 4e 11 1e 80 7c 50 70 ea 1b 68 16 d9 e6 93 b7 |}N...|Pp..h.....| +00000260 fb 6f 0d 6e ce 8b d2 7c 86 70 c3 e9 ed 35 3c 29 |.o.n...|.p...5<)| +00000270 c7 d8 6c 8f 43 c9 a1 7a 4a ae 19 22 6e e3 85 7e |..l.C..zJ.."n..~| +00000280 a0 5d 7f 19 a5 b7 25 ad d7 1a 5f 42 02 42 00 d8 |.]....%..._B.B..| +00000290 6a 25 47 2a 0e 1a 38 51 1c 73 aa 2d 10 9e 4b 65 |j%G*..8Q.s.-..Ke| +000002a0 56 34 72 e5 02 09 f6 30 ce a8 a0 59 75 7b 13 42 |V4r....0...Yu{.B| +000002b0 1e 31 f3 dd 08 a9 65 df 2d e6 aa 29 5d 9a 5c eb |.1....e.-..)].\.| +000002c0 d3 67 af 29 4e d2 76 e5 17 1d 7e e7 0a 50 c4 d0 |.g.)N.v...~..P..| +000002d0 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| +000002e0 00 00 00 00 00 00 00 00 00 00 00 8b ef 24 70 ef |.............$p.| +000002f0 b9 b3 fd 59 49 62 b7 18 9c bc 7f 74 06 21 21 ab |...YIb.....t.!!.| +00000300 9c 4d cf 70 0c 6b 3b d3 d4 12 51 a7 f9 09 65 d1 |.M.p.k;...Q...e.| +00000310 ce b7 28 01 c1 e9 0b e4 41 55 b6 |..(.....AU.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 b8 19 a7 e2 35 |..........@....5| -00000010 8a be 5f 4c 91 d2 db 3f f3 42 90 8e b5 7f ea f7 |.._L...?.B......| -00000020 52 3e 61 2f 4d ef 25 8d ce 82 77 22 05 6f 0d b6 |R>a/M.%...w".o..| -00000030 04 c1 f0 f0 a2 9d bf 80 a9 f5 e1 62 5c e2 30 ef |...........b\.0.| -00000040 83 e7 c5 78 de 8f 17 4e d3 57 dd |...x...N.W.| +00000000 14 03 03 00 01 01 16 03 03 00 40 af 82 f6 ba d1 |..........@.....| +00000010 e8 f9 c5 58 0e ba 94 ec 98 68 b3 20 5b db 4e 8c |...X.....h. [.N.| +00000020 f5 00 29 e8 9a c1 34 35 ac 77 af e2 a0 6a 6f 45 |..)...45.w...joE| +00000030 05 56 d4 a0 5b 75 19 c6 1b 8a c8 65 04 ed 3d f3 |.V..[u.....e..=.| +00000040 84 e5 1b c0 26 31 5d 03 d5 b4 31 |....&1]...1| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 cb 79 13 ea 9e 7a 63 8f 5a 2b 8c |......y...zc.Z+.| -00000020 3a f3 bb 7e dc ff d1 2c 4a a6 4a aa ad bf 44 b8 |:..~...,J.J...D.| -00000030 cb 67 ce 3d f0 15 03 03 00 30 00 00 00 00 00 00 |.g.=.....0......| -00000040 00 00 00 00 00 00 00 00 00 00 f4 15 a0 f0 64 d1 |..............d.| -00000050 dd 5f 14 66 6c ce 51 95 bc b5 0b f8 4f 42 48 57 |._.fl.Q.....OBHW| -00000060 cf f3 09 62 75 0d 3e 64 64 e0 |...bu.>dd.| +00000010 00 00 00 00 00 2e a5 7c 6f cc f7 44 1a 38 99 4a |.......|o..D.8.J| +00000020 2e a4 4b 79 bf ee b6 c9 12 57 f5 2e 98 dd 1d 2a |..Ky.....W.....*| +00000030 5b 79 d5 ef 44 15 03 03 00 30 00 00 00 00 00 00 |[y..D....0......| +00000040 00 00 00 00 00 00 00 00 00 00 3d fe 37 cb 65 03 |..........=.7.e.| +00000050 13 ce 3d 3b c2 18 c2 27 f9 a4 b7 fc e6 37 eb 2a |..=;...'.....7.*| +00000060 27 6c 52 38 2f 3a 61 d4 a9 e6 |'lR8/:a...| diff --git a/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/testdata/Client-TLSv12-ClientCert-ECDSA-RSA index 692092e..de57515 100644 --- a/testdata/Client-TLSv12-ClientCert-ECDSA-RSA +++ b/testdata/Client-TLSv12-ClientCert-ECDSA-RSA @@ -17,11 +17,11 @@ 000000f0 bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 |.).0.........._X| 00000100 cb 3b 74 |.;t| >>> Flow 2 (server to client) -00000000 16 03 03 00 5d 02 00 00 59 03 03 ed c3 6f 59 34 |....]...Y....oY4| -00000010 78 33 49 00 68 50 1f a5 aa 93 45 9a 87 34 c4 4e |x3I.hP....E..4.N| -00000020 71 b0 ab 5e 43 f7 a1 5c 89 e8 2f 20 f7 42 d7 2a |q..^C..\../ .B.*| -00000030 a5 fe 16 76 ac 6f cf 20 1d a6 bc d5 9d 27 9d 81 |...v.o. .....'..| -00000040 80 b4 0d 4e 12 89 de 7b 7a 5b a0 2b c0 2f 00 00 |...N...{z[.+./..| +00000000 16 03 03 00 5d 02 00 00 59 03 03 f8 3d 7c a4 a8 |....]...Y...=|..| +00000010 11 e3 56 0f 1c 7e 2e 7c 50 7e 75 5c de 1c 51 8e |..V..~.|P~u\..Q.| +00000020 de d3 8a 84 d2 90 84 f9 e9 07 d5 20 98 6a a8 c1 |........... .j..| +00000030 f4 28 bd 0f 6a 25 a5 26 3d 8d 35 b6 3e bb 77 c6 |.(..j%.&=.5.>.w.| +00000040 8e ab 36 bd 7d c8 a9 b1 5b 30 0f b2 c0 2f 00 00 |..6.}...[0.../..| 00000050 11 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 17 |................| 00000060 00 00 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 |......Y...U..R..| 00000070 4f 30 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 |O0..K0..........| @@ -61,18 +61,18 @@ 00000290 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 |s..Cw.......@.a.| 000002a0 4c 72 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 |Lr+...F..M...>..| 000002b0 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 |.B...=.`.\!.;...| -000002c0 16 03 03 00 ac 0c 00 00 a8 03 00 1d 20 d9 02 16 |............ ...| -000002d0 ba b6 db c0 c6 65 6d fb b8 69 dc 04 1a 8d 4a 36 |.....em..i....J6| -000002e0 27 6b f0 53 c3 72 56 1a 99 07 0f b9 79 08 04 00 |'k.S.rV.....y...| -000002f0 80 5d c6 1e a2 20 7d ae 35 e6 20 2f ff 7a 7b 8d |.]... }.5. /.z{.| -00000300 3f fd 49 d4 ce 26 f7 d0 c2 51 2a 42 03 26 b7 30 |?.I..&...Q*B.&.0| -00000310 af 5f 7d 34 1d 7d 37 ef 8a 1c e6 be 19 99 f1 30 |._}4.}7........0| -00000320 2e 26 6d 7b 83 cd 6e 26 c4 03 f5 7a 30 8f bf e3 |.&m{..n&...z0...| -00000330 c1 64 da 43 fc f0 32 c9 a2 68 e4 97 d0 34 8a c4 |.d.C..2..h...4..| -00000340 fc f8 bb 61 ec df 69 f7 d0 d7 1e 19 c0 5b 21 86 |...a..i......[!.| -00000350 eb 79 93 46 3b 7a 50 83 41 8b d3 7c 59 d5 34 8a |.y.F;zP.A..|Y.4.| -00000360 0c b5 70 e4 86 38 3a 6c 11 04 57 d6 94 c0 78 c7 |..p..8:l..W...x.| -00000370 91 16 03 03 00 3a 0d 00 00 36 03 01 02 40 00 2e |.....:...6...@..| +000002c0 16 03 03 00 ac 0c 00 00 a8 03 00 1d 20 5f c1 31 |............ _.1| +000002d0 d7 64 f0 0b 72 6a 66 2c 49 d7 d1 9c dd 6f e3 3a |.d..rjf,I....o.:| +000002e0 ab 2c 78 6d ca b0 ed 16 26 65 9f ff 66 08 04 00 |.,xm....&e..f...| +000002f0 80 a6 91 d0 03 b8 d2 67 48 69 16 8e 30 dc 5b 3f |.......gHi..0.[?| +00000300 ac 4d e4 33 5f 46 e7 0c 49 a0 71 9d 8c 60 63 f2 |.M.3_F..I.q..`c.| +00000310 2d ff 9e 89 21 7d af 71 ce 41 6b d2 22 fc 1f bd |-...!}.q.Ak."...| +00000320 a9 9e 15 2c d7 c3 cb 69 6d df 23 07 7c 13 e9 2b |...,...im.#.|..+| +00000330 7d 05 f0 18 1e 86 c8 37 ad cd 9e 39 26 0c 8a 9b |}......7...9&...| +00000340 12 90 60 12 95 06 e9 bb f2 46 41 20 10 f5 64 ea |..`......FA ..d.| +00000350 66 13 cb 8e 51 7e 41 78 2a 40 fa 15 e2 0d 5b 37 |f...Q~Ax*@....[7| +00000360 a7 a8 4a f6 8e 93 82 2a a2 91 06 66 4e 49 72 68 |..J....*...fNIrh| +00000370 f9 16 03 03 00 3a 0d 00 00 36 03 01 02 40 00 2e |.....:...6...@..| 00000380 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................| 00000390 08 04 08 05 08 06 04 01 05 01 06 01 03 03 02 03 |................| 000003a0 03 01 02 01 03 02 02 02 04 02 05 02 06 02 00 00 |................| @@ -114,27 +114,27 @@ 00000210 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b| 00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......| 00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 93 0f 00 |...._X.;t.......| -00000240 00 8f 04 03 00 8b 30 81 88 02 42 01 a3 80 63 a4 |......0...B...c.| -00000250 49 60 35 5c 06 87 9f 7f ae 40 37 d0 64 58 b2 60 |I`5\.....@7.dX.`| -00000260 61 59 8b 6d a6 d9 55 67 81 f6 7e 9c de 40 69 00 |aY.m..Ug..~..@i.| -00000270 42 e1 2e 67 0d 48 cf 23 a7 28 f2 e0 9e 26 61 20 |B..g.H.#.(...&a | -00000280 4f 50 b6 e3 85 0b f5 f6 96 ec 03 32 35 02 42 01 |OP.........25.B.| -00000290 bd 3b 3e d6 03 98 b5 09 9a aa a9 73 1d 98 6a a5 |.;>........s..j.| -000002a0 29 ff e5 b3 f8 1f 58 2a a1 92 ea 2d 6d e9 71 d3 |).....X*...-m.q.| -000002b0 ce 04 46 ef d6 fb e4 5e e3 70 19 01 1a 22 85 70 |..F....^.p...".p| -000002c0 06 ec 15 bd ff ef af ed 2b 6d 00 97 cb 67 1f cb |........+m...g..| -000002d0 f6 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 |...........(....| -000002e0 00 00 00 00 80 da 31 59 19 74 39 ff a4 8c 30 1b |......1Y.t9...0.| -000002f0 25 fd 6b 25 57 ef 26 57 bd a1 df 90 4e d6 6a 47 |%.k%W.&W....N.jG| -00000300 96 08 54 92 |..T.| +00000240 00 8f 04 03 00 8b 30 81 88 02 42 01 0f 51 5e 59 |......0...B..Q^Y| +00000250 78 34 8f 99 03 da 07 66 3b 0d 48 b2 79 57 e2 d5 |x4.....f;.H.yW..| +00000260 d2 c2 f3 81 8e 25 98 81 e2 9a f7 1f 02 99 b0 7d |.....%.........}| +00000270 1c d1 1f e4 ef d7 bc a1 ad 67 c7 a9 cc 4f 67 58 |.........g...OgX| +00000280 8b 1e 8c 3f 04 73 31 53 60 aa 67 33 27 02 42 01 |...?.s1S`.g3'.B.| +00000290 f1 66 ba 8f ec 9e 3f 76 76 ac 7a e7 56 cb fb 46 |.f....?vv.z.V..F| +000002a0 f4 9b 64 03 3a 72 5a d7 cf 49 39 69 26 19 68 52 |..d.:rZ..I9i&.hR| +000002b0 8b 98 8e ea d3 8e d9 6d 93 f5 e8 23 cd 20 a8 5a |.......m...#. .Z| +000002c0 4c 24 10 70 bd a2 ae a3 b1 4f 38 17 dd b9 f5 93 |L$.p.....O8.....| +000002d0 4b 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 |K..........(....| +000002e0 00 00 00 00 e1 2b da c6 4a 5c d2 03 c0 7e f0 eb |.....+..J\...~..| +000002f0 a0 4b ed a1 7d e4 45 93 ec f9 37 a0 5b 7e bb 64 |.K..}.E...7.[~.d| +00000300 af d4 fc ac |....| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 0e 1f ce 8a 46 |..........(....F| -00000010 77 28 6d e2 fc c4 e4 39 70 6b ab 6e 14 14 2a 34 |w(m....9pk.n..*4| -00000020 13 a0 5b c5 95 f5 fa a9 a2 f6 60 20 e3 1f c5 84 |..[.......` ....| -00000030 9c 00 5e |..^| +00000000 14 03 03 00 01 01 16 03 03 00 28 d3 4a 1e 2b ea |..........(.J.+.| +00000010 26 12 c9 fd b0 7b e6 bf e4 bb b6 d2 6b b4 3c 05 |&....{......k.<.| +00000020 1f 6c 46 44 5e 25 e6 f9 80 c8 b9 16 19 59 68 90 |.lFD^%.......Yh.| +00000030 5a 90 16 |Z..| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 88 d1 a4 |................| -00000010 c9 1b a6 a5 21 4d 93 e8 04 8b 3b 69 a9 2f bd 7d |....!M....;i./.}| -00000020 97 c1 3d 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..=.............| -00000030 ba 48 db 22 9e ae d8 a9 24 b7 a6 52 13 92 68 d6 |.H."....$..R..h.| -00000040 aa b5 |..| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 35 25 df |.............5%.| +00000010 1f 16 81 00 e3 c4 9e 45 e2 a1 ef 54 72 66 99 3d |.......E...Trf.=| +00000020 30 13 25 15 03 03 00 1a 00 00 00 00 00 00 00 02 |0.%.............| +00000030 16 a5 e9 36 c1 fb 02 d7 c8 7a aa bc aa 77 7b 5c |...6.....z...w{\| +00000040 4f a1 |O.| diff --git a/testdata/Client-TLSv13-ClientCert-ECDSA-RSA b/testdata/Client-TLSv13-ClientCert-ECDSA-RSA index 8984790..db13bd6 100644 --- a/testdata/Client-TLSv13-ClientCert-ECDSA-RSA +++ b/testdata/Client-TLSv13-ClientCert-ECDSA-RSA @@ -17,124 +17,124 @@ 000000f0 bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 |.).0.........._X| 00000100 cb 3b 74 |.;t| >>> Flow 2 (server to client) -00000000 16 03 03 00 7a 02 00 00 76 03 03 ea 8b 99 cb 5b |....z...v......[| -00000010 d8 fb e9 14 7f 17 20 9c b8 41 01 dd ce 8a 90 4e |...... ..A.....N| -00000020 a9 f0 fb eb 71 37 24 02 d2 ee 96 20 00 00 00 00 |....q7$.... ....| +00000000 16 03 03 00 7a 02 00 00 76 03 03 37 0c 23 2f 26 |....z...v..7.#/&| +00000010 2a b0 8d 47 84 3b 9b 9c 7e 0f 0a cd 77 39 6c c2 |*..G.;..~...w9l.| +00000020 7b c0 56 a8 9d 07 a0 ec b6 e5 79 20 00 00 00 00 |{.V.......y ....| 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................| -00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 c8 |..+.....3.$... .| -00000060 c6 52 8e 3c 6f 0d ab 2d be 4c e0 01 c8 af 1f 8e |.R........t| -00000100 69 88 5d 8e a4 fa 02 b0 6f f4 0e 38 cc 95 12 e2 |i.].....o..8....| -00000110 f1 e3 47 89 a6 1d 80 26 cb 23 6e f3 83 1c e4 85 |..G....&.#n.....| -00000120 7b 1a 4d 12 c8 bf ff 07 39 a9 4e 4e d7 45 35 23 |{.M.....9.NN.E5#| -00000130 9b f9 59 6d a5 b0 49 1b 5f e7 42 62 17 00 1e 57 |..Ym..I._.Bb...W| -00000140 53 c5 22 fb 05 89 fd fe 5d de 71 e8 26 fd 6d e3 |S.".....].q.&.m.| -00000150 fc b9 cb 1f d5 d4 84 d1 67 fe 8a a0 74 ff ad ff |........g...t...| -00000160 c8 35 fe c2 9a 17 33 18 51 c2 cd 19 7c dc 5d c5 |.5....3.Q...|.].| -00000170 7c e6 d0 38 ab 28 0b 8c 78 51 aa 7f ef f0 9a c3 ||..8.(..xQ......| -00000180 df 26 d2 bc 1b b6 98 b1 16 35 9d f0 73 b7 15 f7 |.&.......5..s...| -00000190 7d 9f 3e fe 4c 75 e7 c7 5d cb c2 e5 29 4a 30 32 |}.>.Lu..]...)J02| -000001a0 e2 da 3c 2c 16 ba 89 41 28 5c 33 75 b3 ed d1 e6 |..<,...A(\3u....| -000001b0 4f f6 bb 33 62 53 9d be fe d3 53 b5 bd 3e e3 b5 |O..3bS....S..>..| -000001c0 0a 37 67 60 33 c3 72 a8 ea 55 73 3c b2 7f ed 8b |.7g`3.r..Us<....| -000001d0 59 5e 44 e4 76 0d 1e 3c 3e 1c 9c 8c 86 3d 0a a3 |Y^D.v..<>....=..| -000001e0 78 bd 13 77 eb dc 22 e5 96 ff ae 44 94 cd ef ae |x..w.."....D....| -000001f0 ca 64 ec 06 a1 38 49 17 ce a5 c4 34 86 fd 55 1f |.d...8I....4..U.| -00000200 32 31 d5 b0 8c d6 b5 bc b8 29 29 97 b5 39 a0 f8 |21.......))..9..| -00000210 b1 b5 72 24 ff ce 6f 7d 6a 0d 18 26 8f 9a e8 d3 |..r$..o}j..&....| -00000220 e6 e0 7c 9c 56 45 ca 48 44 69 05 53 40 eb 96 c5 |..|.VE.HDi.S@...| -00000230 17 aa 28 56 20 ee 82 fd de d1 55 b8 e9 27 ae 3d |..(V .....U..'.=| -00000240 e1 44 d6 0b b9 7a 25 77 b0 f1 be 64 ae cc 0d 44 |.D...z%w...d...D| -00000250 af 57 32 9f cf bc c0 07 00 0b 19 97 08 0a d5 50 |.W2............P| -00000260 20 0e ef d5 1e 2e 68 82 ae 2d 84 47 3d 9b 5b 24 | .....h..-.G=.[$| -00000270 55 95 b2 93 e0 60 a2 cd e5 72 69 b3 e2 de da 70 |U....`...ri....p| -00000280 76 88 be 1f 5a 8e 7a d8 ff 94 db b0 92 b2 a1 a1 |v...Z.z.........| -00000290 26 5b 3b d5 5e 67 16 b7 6a 9f dc ab 21 7e df 6e |&[;.^g..j...!~.n| -000002a0 2a 73 e9 20 40 4b c8 34 fc 4b be f6 d8 ba 78 d7 |*s. @K.4.K....x.| -000002b0 a4 c2 ed a9 52 f9 ea 88 67 5e 10 92 8f ba 83 cd |....R...g^......| -000002c0 19 79 82 c5 76 06 d9 98 9f 68 2e 34 82 2f 9a 41 |.y..v....h.4./.A| -000002d0 fb 63 b6 8c 79 56 62 9d bb bc b5 22 ab 28 35 f7 |.c..yVb....".(5.| -000002e0 bc c6 a8 6b e7 86 01 c3 6c e5 88 28 57 09 65 31 |...k....l..(W.e1| -000002f0 b2 5c 0a 60 46 af 94 2c d4 37 49 9b 4c e4 4b bb |.\.`F..,.7I.L.K.| -00000300 fb 0d 87 94 82 11 09 26 04 6f ec e9 a6 f4 9c ca |.......&.o......| -00000310 79 a0 d0 48 32 5a 02 58 70 81 d0 b6 6d 77 2f 6f |y..H2Z.Xp...mw/o| -00000320 4e 9b db ca 82 38 ed a6 60 8e e2 b6 14 33 f5 02 |N....8..`....3..| -00000330 4b 97 a4 86 2f 43 9d ee 88 2c 1c 58 7e 47 30 cc |K.../C...,.X~G0.| -00000340 ec 0d aa 22 13 60 be e2 c9 c4 59 90 67 96 9b 2a |...".`....Y.g..*| -00000350 41 79 49 00 71 80 e9 0d 12 c3 17 03 03 00 99 ec |AyI.q...........| -00000360 f5 a1 45 64 61 fc 61 35 d5 2f bf 20 02 68 0b 10 |..Eda.a5./. .h..| -00000370 df c4 4b e7 2c 43 bc f5 3d 0b 7e 9f a4 71 09 2c |..K.,C..=.~..q.,| -00000380 a6 cf f4 f4 b4 2c 08 0c 03 50 ac 47 74 ad 24 f1 |.....,...P.Gt.$.| -00000390 04 f3 d4 83 42 3f 35 a5 57 ff ab 59 0c 9a a2 ca |....B?5.W..Y....| -000003a0 6c 30 b7 87 73 af 53 f9 1d 6b e7 44 ec d1 bd 14 |l0..s.S..k.D....| -000003b0 15 09 cf ff 82 5e a2 6d ba 00 53 b8 b3 7c 0e e5 |.....^.m..S..|..| -000003c0 d1 e2 a2 38 25 88 aa ee 93 c8 d9 d1 88 42 42 90 |...8%........BB.| -000003d0 43 8d 22 d8 48 02 57 22 6a f4 e9 23 71 f0 64 30 |C.".H.W"j..#q.d0| -000003e0 6a 68 12 a5 3c 8c 61 5e bc 73 91 6a 01 3a 14 14 |jh..<.a^.s.j.:..| -000003f0 86 7c 4d f5 aa cc 2f f5 17 03 03 00 35 7e f6 f5 |.|M.../.....5~..| -00000400 6b 75 e2 63 64 5a 6b 9b ce 6b 76 d7 47 bc 1b 47 |ku.cdZk..kv.G..G| -00000410 9e 68 25 fe 47 2b 06 a9 72 d0 a7 3f 23 3d 71 4a |.h%.G+..r..?#=qJ| -00000420 da 29 fb e3 dd ee e6 f6 a5 32 cc eb da 61 2b 52 |.).......2...a+R| -00000430 24 26 |$&| +00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 5e |..+.....3.$... ^| +00000060 9a da 1d cb 90 03 f2 d2 23 e3 54 fc 3d 9b 8c 92 |........#.T.=...| +00000070 42 df cf 7a 3d 47 3f 66 a4 a6 7a 07 44 76 5c 14 |B..z=G?f..z.Dv\.| +00000080 03 03 00 01 01 17 03 03 00 17 53 54 e6 de 6a af |..........ST..j.| +00000090 c2 d9 b8 39 b6 ae 3e 9f 54 60 e1 fa 29 5a fb 16 |...9..>.T`..)Z..| +000000a0 20 17 03 03 00 42 f4 a5 7f e3 e7 ba 6a 88 e1 f2 | ....B......j...| +000000b0 fd 25 3e ba 05 00 29 77 ff 69 6e e0 ac 50 99 50 |.%>...)w.in..P.P| +000000c0 ac 1e bd 8c 52 e6 28 5d 67 bb bb 20 61 69 5b 97 |....R.(]g.. ai[.| +000000d0 7f 29 79 97 bf 13 24 25 ad 3b 01 78 c4 a4 4e 9a |.)y...$%.;.x..N.| +000000e0 06 d6 20 da 63 27 97 8d 17 03 03 02 6d 79 7e 9e |.. .c'......my~.| +000000f0 01 98 a9 7c ba 63 43 2b 21 b1 bc 2c b2 17 c2 35 |...|.cC+!..,...5| +00000100 76 f2 30 01 69 45 d4 56 e0 5a 2c 62 aa 6f a8 1f |v.0.iE.V.Z,b.o..| +00000110 b8 31 df be 6f 3f 60 16 dc 61 5c 9f 99 a9 63 7d |.1..o?`..a\...c}| +00000120 7e 2b d2 ae 02 46 12 db be 51 9e 15 dd 1c 96 b0 |~+...F...Q......| +00000130 74 69 20 c0 e1 78 46 01 a6 23 72 28 ba c7 a3 48 |ti ..xF..#r(...H| +00000140 1e dc 0b 57 c9 b4 39 88 3d 39 c7 6c 38 c7 3a 29 |...W..9.=9.l8.:)| +00000150 a4 45 79 10 04 61 cd db df 5b 88 c1 35 4b 38 ea |.Ey..a...[..5K8.| +00000160 6d 72 57 9f e0 2e 37 61 3d c8 aa b2 25 a6 11 5c |mrW...7a=...%..\| +00000170 09 e2 3a 17 d3 c5 37 2f a7 b4 73 fe e2 61 df 1d |..:...7/..s..a..| +00000180 cd 4f 72 4a 67 c3 c7 e2 53 78 61 78 2c 37 44 12 |.OrJg...Sxax,7D.| +00000190 4d 0e 8c 14 0b de 3b a4 cf ad 8f d4 74 61 77 4b |M.....;.....tawK| +000001a0 36 2d f2 8f 68 95 38 9d e2 9f cf cc 03 15 89 b9 |6-..h.8.........| +000001b0 96 c4 47 e5 2f 65 0a 5c 5d 8f 5c 64 9d c8 76 d2 |..G./e.\].\d..v.| +000001c0 5d a7 90 4d f5 84 2d 31 2d 6c bd ee 0d 45 2b 50 |]..M..-1-l...E+P| +000001d0 79 f7 8c 34 40 f9 bc f4 38 b3 56 a9 6b ca 54 50 |y..4@...8.V.k.TP| +000001e0 19 f8 9a 73 74 9b 0a 92 ee 22 53 05 01 38 43 3a |...st...."S..8C:| +000001f0 49 fe 2d e9 39 c1 76 b0 04 df 8a 3d cc fc 9b 84 |I.-.9.v....=....| +00000200 cd 22 ba 40 24 69 93 b9 c5 b3 ed fd ad 94 1b 83 |.".@$i..........| +00000210 b5 07 a9 e7 94 14 4b c1 59 89 78 56 03 28 29 c3 |......K.Y.xV.().| +00000220 a8 a4 96 14 5a 51 9a 50 f9 34 3c 5a 76 8f 74 68 |....ZQ.P.4..K..k*D?.#..U| +000002f0 a0 11 51 04 0b 82 02 d9 24 85 13 2e d1 29 44 9a |..Q.....$....)D.| +00000300 15 7f a4 1b c4 f5 36 44 88 9a 6e 5a 1e 2f 14 fa |......6D..nZ./..| +00000310 d0 e7 fc 6a fa e5 f3 4a 55 20 73 9b e4 73 2e 47 |...j...JU s..s.G| +00000320 88 25 b7 69 d9 28 fe 50 8c fc f2 94 29 84 c4 7f |.%.i.(.P....)...| +00000330 d6 b2 eb 28 fa 51 8e ff 00 09 35 d3 b2 32 3a c6 |...(.Q....5..2:.| +00000340 bb 91 a7 c4 b7 88 df 4b f7 09 ef e7 e1 92 60 cd |.......K......`.| +00000350 de 34 4f 39 ee b8 ce 50 6a b9 17 03 03 00 99 64 |.4O9...Pj......d| +00000360 76 ab 48 eb 68 7d a6 68 60 aa c2 93 bd 31 81 c8 |v.H.h}.h`....1..| +00000370 b6 15 ba d1 54 94 04 1b 4b 29 86 e1 12 84 ad d5 |....T...K)......| +00000380 ba eb 4a 7a 7a a8 56 41 04 8c 84 c7 83 46 8c 50 |..Jzz.VA.....F.P| +00000390 c4 e3 02 d0 28 a4 fe 24 c4 b8 96 13 4f 87 27 ec |....(..$....O.'.| +000003a0 6b e3 84 4b 97 13 65 fa 1e 5e 9d ac 85 ea a0 3d |k..K..e..^.....=| +000003b0 67 96 e5 ec 88 84 6b 79 d9 16 55 c1 1c 72 17 aa |g.....ky..U..r..| +000003c0 9b 49 13 86 d4 39 0d 2a c8 88 b3 5f f5 11 cb 5f |.I...9.*..._..._| +000003d0 bd 22 57 2c bc c1 01 72 b9 c3 f5 d9 a2 3b 8e ff |."W,...r.....;..| +000003e0 44 b2 82 b6 5b 35 75 b5 7a 50 40 81 4e a7 2d 40 |D...[5u.zP@.N.-@| +000003f0 21 28 d9 c4 d9 e5 07 e1 17 03 03 00 35 23 ab b2 |!(..........5#..| +00000400 60 56 47 6a fe cb 0e 54 22 d5 8f 29 0a 34 e6 82 |`VGj...T"..).4..| +00000410 5b 10 35 ac 93 97 92 6b 39 5d b8 01 54 9c 86 b0 |[.5....k9]..T...| +00000420 41 70 52 88 92 cf dd b7 f8 5d d1 18 e1 1f 78 53 |ApR......]....xS| +00000430 e4 43 |.C| >>> Flow 3 (client to server) -00000000 14 03 03 00 01 01 17 03 03 02 1e 67 f8 08 c4 15 |...........g....| -00000010 47 a9 da 91 df f1 61 0f 50 21 f6 da dd a9 a6 e4 |G.....a.P!......| -00000020 00 05 29 62 d2 cc fe 14 57 a2 aa 46 16 b3 46 6e |..)b....W..F..Fn| -00000030 82 87 dc bb 1a d9 e7 c6 e9 1a 3b 7e a5 94 9b 7e |..........;~...~| -00000040 bb 07 b8 f3 de cc f1 85 d5 ee ff 0b 5a 19 c1 e3 |............Z...| -00000050 5f 47 f4 81 f4 d3 2d 85 f8 38 90 00 10 54 9a 3e |_G....-..8...T.>| -00000060 56 e4 99 a5 31 b1 dc d4 77 fe 28 3a b4 3e 63 42 |V...1...w.(:.>cB| -00000070 bc 05 c7 8a e5 d9 01 5c c9 18 39 1e 62 4f b4 58 |.......\..9.bO.X| -00000080 d3 9a 6a e1 a4 d3 ef 7f b8 0f 35 ac 2a 4a ba 77 |..j.......5.*J.w| -00000090 24 1e 24 6e 0e a2 8e f1 ba 5f fe 24 03 ed 1d e7 |$.$n....._.$....| -000000a0 43 2d fb bb 2e a9 a5 9a 18 11 39 99 a1 5a b7 92 |C-........9..Z..| -000000b0 37 91 f2 80 b2 f6 57 87 f9 a5 d9 da 36 b5 db 1a |7.....W.....6...| -000000c0 28 d8 9e f7 92 6f cf 0c 57 9a 95 42 ef 6a 50 f6 |(....o..W..B.jP.| -000000d0 38 4f 74 52 09 34 ca 8a d8 c7 a2 d2 69 bb db 13 |8OtR.4......i...| -000000e0 b1 ef f2 6d d3 f0 dd 5d b7 93 25 87 84 cd 87 6d |...m...]..%....m| -000000f0 c7 24 99 2b c8 02 25 1c 58 bc 98 03 33 15 ee 3e |.$.+..%.X...3..>| -00000100 96 d0 af 82 c7 74 71 ec ef a6 eb 88 20 55 1b fa |.....tq..... U..| -00000110 ea 01 38 5b 68 77 f1 3b 2a e6 d1 96 bc 28 b3 97 |..8[hw.;*....(..| -00000120 47 94 14 3f 6b 73 82 bf b0 ba fe 45 2a 45 45 1c |G..?ks.....E*EE.| -00000130 30 68 f5 74 07 15 18 00 a7 4f 62 df 7c ff 4c 0a |0h.t.....Ob.|.L.| -00000140 93 d6 60 8b 1f 0e 7f d3 88 43 90 f6 18 05 f1 ae |..`......C......| -00000150 ac 04 63 8b 43 b8 11 74 b1 87 e6 bc 2d 72 4a 2e |..c.C..t....-rJ.| -00000160 75 ab 16 5e 0e bc 76 6d d6 0e bc 39 0d 3c 76 01 |u..^..vm...9.fDcKC.%(D.-.| -000001b0 39 0e cd 15 a3 04 d9 db 4f a4 03 cb d2 84 da 41 |9.......O......A| -000001c0 5c 60 bf 00 77 19 68 b1 50 99 c2 88 d2 56 1e 29 |\`..w.h.P....V.)| -000001d0 c9 8c 83 98 7a 2f 04 e6 d6 09 5c 27 af a7 69 c4 |....z/....\'..i.| -000001e0 f7 4a ed b5 db d3 7a aa 75 f1 b2 8d 87 15 9a d1 |.J....z.u.......| -000001f0 00 fa 7f 58 06 2d 72 2b f7 27 b3 5b 76 57 21 35 |...X.-r+.'.[vW!5| -00000200 80 ce 8e bd e4 bb 45 01 c4 6b 43 f1 44 0a 5f 21 |......E..kC.D._!| -00000210 76 48 ae ce 8e 1d ba f7 7c 4f ae a2 d8 77 ce 9c |vH......|O...w..| -00000220 6d 69 b7 1e 78 ab 02 ed 15 17 03 03 00 a3 84 ed |mi..x...........| -00000230 ba 37 b6 6f 96 68 ef 9e b7 c6 23 5a 9f 1b ed ad |.7.o.h....#Z....| -00000240 3b 5d ab d4 22 d8 3e ab db db c5 b9 57 f8 68 d1 |;]..".>.....W.h.| -00000250 93 d5 36 fe 0c c0 fe 29 88 8b 63 ac 0e 06 4e bd |..6....)..c...N.| -00000260 9e b9 24 65 b5 9c e7 b9 58 4c 8a 07 10 9c 17 f7 |..$e....XL......| -00000270 c0 67 af ff c8 ff fc 87 1b fa c8 21 21 17 2d 43 |.g.........!!.-C| -00000280 f5 fc 4f 0d bf 01 58 b6 f1 58 08 39 f4 0d 94 69 |..O...X..X.9...i| -00000290 8f f0 c1 14 93 41 56 32 41 11 84 58 73 13 69 2a |.....AV2A..Xs.i*| -000002a0 ed 2a 34 61 73 8d 47 41 62 33 39 66 fa 3d 2a e5 |.*4as.GAb39f.=*.| -000002b0 bf 09 d6 c0 1e 3c 98 b3 86 a6 87 b5 a7 d2 cf d9 |.....<..........| -000002c0 dd f8 2e 86 f7 13 84 4a f7 3b ec 8e e5 06 f5 cd |.......J.;......| -000002d0 42 17 03 03 00 35 b2 38 87 30 58 9e 03 6e 44 dd |B....5.8.0X..nD.| -000002e0 fb 87 11 3a a0 e7 c1 2d 74 3b 35 d0 3f bc de cd |...:...-t;5.?...| -000002f0 71 61 8b 7c a5 7e c6 2d 76 67 44 9e 75 e5 9b 3b |qa.|.~.-vgD.u..;| -00000300 c5 2b 42 8a 4a 7f 0e 12 4c 2e 0f 17 03 03 00 17 |.+B.J...L.......| -00000310 d3 61 ed 75 dd 2e ee dd 79 fe d1 7c 4d 23 b1 95 |.a.u....y..|M#..| -00000320 ea 14 d6 27 d0 02 46 17 03 03 00 13 84 c1 07 6f |...'..F........o| -00000330 1c c6 22 a8 ae 6d a8 e8 62 54 ac b2 53 57 bb |.."..m..bT..SW.| +00000000 14 03 03 00 01 01 17 03 03 02 1e 19 c5 11 9d 64 |...............d| +00000010 8f f5 a9 21 53 fa cc 91 67 30 39 c0 77 d6 35 7b |...!S...g09.w.5{| +00000020 b8 a3 ae 44 8a 9a b1 68 5a 20 72 a6 ae 3a 1b 9f |...D...hZ r..:..| +00000030 03 eb d9 ed 91 20 49 ba 88 39 99 1c 4e 3a 2b 1b |..... I..9..N:+.| +00000040 42 b7 a3 97 a3 a3 6c 7e 3b 4c c1 74 dc 71 e6 14 |B.....l~;L.t.q..| +00000050 6c 5a 36 12 cb 87 a6 75 ce b3 e3 a8 f2 c8 36 12 |lZ6....u......6.| +00000060 3d c8 b8 2a 36 e4 40 38 3e 20 1d de 2a 31 b1 04 |=..*6.@8> ..*1..| +00000070 86 cb 9b c1 f3 fc 01 67 7e 40 0b b8 c4 fa 8f a0 |.......g~@......| +00000080 a7 5b 24 43 a9 d3 eb 55 99 ec 0b 19 cb ec 19 97 |.[$C...U........| +00000090 c8 0f c0 5e 8c b2 b1 93 80 70 7c 0b aa 7c 6c 44 |...^.....p|..|lD| +000000a0 1a 11 dc bd 0d 97 18 f3 ca c6 50 68 ca 77 ab 18 |..........Ph.w..| +000000b0 79 a9 8b 73 13 48 90 c3 4a cd ae f2 60 ea 0c 20 |y..s.H..J...`.. | +000000c0 eb ad 84 fb 2f 01 7e 2c f6 7d ea da 22 59 5f 88 |..../.~,.}.."Y_.| +000000d0 ff 10 19 81 d5 29 1b 0f 36 7b 84 66 eb bf e3 f9 |.....)..6{.f....| +000000e0 1c 68 fa 03 93 3e ba c6 58 e2 a9 57 94 8c a8 29 |.h...>..X..W...)| +000000f0 e2 f9 4b 6d 85 01 e8 f2 11 a2 04 38 73 8e 69 49 |..Km.......8s.iI| +00000100 4b 7f ca be aa 5f 50 ac 82 16 e6 92 78 87 13 f4 |K...._P.....x...| +00000110 fc 21 e8 2d 89 d0 f7 fb 73 0b f3 b7 6a 67 24 e8 |.!.-....s...jg$.| +00000120 d9 33 59 49 d6 88 24 a2 66 f5 c8 4d fe 88 93 77 |.3YI..$.f..M...w| +00000130 f9 3f ee ae 0b 6a 23 7a 8f b7 66 d4 68 7d 38 51 |.?...j#z..f.h}8Q| +00000140 85 0a a0 f5 03 f6 e8 2f cd 0b ac 58 64 82 38 20 |......./...Xd.8 | +00000150 f2 72 0a 85 83 55 cb db 62 59 f4 40 08 28 f9 8a |.r...U..bY.@.(..| +00000160 47 a2 ea a1 1b e1 4c 0a a4 74 cb a2 11 6f e5 68 |G.....L..t...o.h| +00000170 e4 ff 38 b0 a5 fc 21 9e eb de 43 b6 e7 27 cf 9a |..8...!...C..'..| +00000180 80 23 59 a2 e9 a8 12 ae 47 09 5c 48 c2 cb c8 e0 |.#Y.....G.\H....| +00000190 a6 fa 81 c5 49 a4 77 4b d3 83 0a ce 6e a5 2b 88 |....I.wK....n.+.| +000001a0 f2 f5 12 2f 0e 7e 10 20 5b c7 31 39 54 ed 19 33 |.../.~. [.19T..3| +000001b0 5c 94 b5 56 16 fa 0c b0 ec 28 76 fa 38 ca 08 c6 |\..V.....(v.8...| +000001c0 13 c3 1f 8a 20 35 73 4b bb bf d8 96 65 de cd f3 |.... 5sK....e...| +000001d0 44 d4 5b 3d 54 aa ac 53 a9 cc 31 99 86 22 5a f9 |D.[=T..S..1.."Z.| +000001e0 9e bd f1 f3 74 07 e4 fe f7 3a 35 44 e5 c6 48 3f |....t....:5D..H?| +000001f0 a3 81 1e 67 96 51 0f e6 7d 43 67 9c 12 6c dd 91 |...g.Q..}Cg..l..| +00000200 c4 f9 20 4d 88 41 fc 40 c5 ee c2 11 fb f1 67 da |.. M.A.@......g.| +00000210 7b b6 d0 1b f8 6e f7 8b 07 f2 9e 12 56 dc 75 31 |{....n......V.u1| +00000220 cd b9 53 62 3f 2f 72 cf ee 17 03 03 00 a4 f9 ec |..Sb?/r.........| +00000230 72 94 94 1c 52 ab 9e 6d 04 5a 26 07 15 3a f5 dd |r...R..m.Z&..:..| +00000240 f3 45 18 20 de 2e 97 f7 6a a4 7c 92 68 aa 71 55 |.E. ....j.|.h.qU| +00000250 b7 7a 3c 8f 54 e7 cc 31 e1 54 9c ad 8e b4 57 11 |.z<.T..1.T....W.| +00000260 1d 79 85 4a da 3f 1b ab fb f4 d4 d9 4d 8a 2e da |.y.J.?......M...| +00000270 68 3e f9 aa 16 52 cc 4e 49 7a 00 bf fc e8 b5 16 |h>...R.NIz......| +00000280 43 0c 6d aa 82 49 3c 16 43 56 55 35 ee 47 c3 1c |C.m..I<.CVU5.G..| +00000290 99 25 6d 30 89 64 5e 23 bf de fc cc 7c 40 94 28 |.%m0.d^#....|@.(| +000002a0 d8 ed ec c2 e2 8b 24 64 64 b6 e8 6c 29 82 b5 ba |......$dd..l)...| +000002b0 d5 59 7a 6f 11 6e cc 30 91 c8 c0 8b 9f dd 13 59 |.Yzo.n.0.......Y| +000002c0 a9 72 18 f6 6e ce 3a 47 6b 4f 26 55 61 bf 20 7a |.r..n.:GkO&Ua. z| +000002d0 d8 c3 17 03 03 00 35 d7 fc bc 10 29 75 c3 70 0a |......5....)u.p.| +000002e0 02 e4 cf 36 20 49 5d 64 78 e9 27 db 2d e3 1a 66 |...6 I]dx.'.-..f| +000002f0 f3 a8 82 7e 64 f0 29 27 81 6c bd b7 a7 86 a2 6a |...~d.)'.l.....j| +00000300 ac 4e 7b da 48 7c d8 9c 39 6c 95 45 17 03 03 00 |.N{.H|..9l.E....| +00000310 17 c9 13 54 e9 22 62 7e 89 17 de 98 52 93 26 76 |...T."b~....R.&v| +00000320 73 a0 7d 2c 60 68 c8 68 17 03 03 00 13 ad 3a 53 |s.},`h.h......:S| +00000330 d1 41 0e 99 26 c8 fb 22 8f e6 d3 a4 1d 83 ff 28 |.A..&..".......(| diff --git a/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/testdata/Server-TLSv10-ECDHE-ECDSA-AES index c5d947c..3bc3a75 100644 --- a/testdata/Server-TLSv10-ECDHE-ECDSA-AES +++ b/testdata/Server-TLSv10-ECDHE-ECDSA-AES @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 51 01 00 00 4d 03 01 5e bf ff e7 c2 |....Q...M..^....| -00000010 c1 98 4a a3 cf 5a e8 8d 8f 19 9e 85 48 5b 92 cc |..J..Z......H[..| -00000020 7d 0c 14 1e 2e 50 5b d7 dd fe ef 00 00 04 c0 0a |}....P[.........| +00000000 16 03 01 00 51 01 00 00 4d 03 01 76 4b 58 ef 57 |....Q...M..vKX.W| +00000010 d5 8d ba b7 0b fe d4 b3 2b a7 76 7c f1 72 59 39 |........+.v|.rY9| +00000020 fa 02 66 88 4a 55 72 15 9e 42 8c 00 00 04 c0 0a |..f.JUr..B......| 00000030 00 ff 01 00 00 20 00 0b 00 04 03 00 01 02 00 0a |..... ..........| 00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................| 00000050 00 00 00 17 00 00 |......| @@ -43,37 +43,37 @@ 00000220 c1 33 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 |.3.......7z..z..| 00000230 2e dd d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 |....i..|V..1x+..| 00000240 78 0d ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 |x.....N6$1{j.9..| -00000250 07 8f 2a 16 03 01 00 b5 0c 00 00 b1 03 00 1d 20 |..*............ | +00000250 07 8f 2a 16 03 01 00 b3 0c 00 00 af 03 00 1d 20 |..*............ | 00000260 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 |/.}.G.bC.(.._.).| 00000270 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |0.........._X.;t| -00000280 00 8b 30 81 88 02 42 00 c3 eb 60 b8 d3 af cb 2d |..0...B...`....-| -00000290 4f ca 46 6d e4 fe 47 41 82 1e d4 14 0f 08 ab b6 |O.Fm..GA........| -000002a0 b8 41 8b 46 f5 28 bb 87 28 73 a0 5c e9 ce f5 56 |.A.F.(..(s.\...V| -000002b0 11 02 17 2c 39 b6 28 6c ec de 12 bf 22 91 3d 06 |...,9.(l....".=.| -000002c0 ac 8e 0a 92 b1 46 69 86 44 02 42 01 fd 70 6e 63 |.....Fi.D.B..pnc| -000002d0 1b 2a 21 47 9b 42 9c d4 4a 38 20 dd 94 05 c4 0f |.*!G.B..J8 .....| -000002e0 5d b2 48 c8 17 90 01 4d 4f 7e 7a ef bb b2 5b 26 |].H....MO~z...[&| -000002f0 7e e1 24 f5 80 93 69 72 3f cf bb 5d 52 ee ec b4 |~.$...ir?..]R...| -00000300 cc 0c 96 1f 93 4c d6 a8 c7 b2 91 f5 6d 16 03 01 |.....L......m...| -00000310 00 04 0e 00 00 00 |......| +00000280 00 89 30 81 86 02 41 00 b5 7c a4 63 77 fa 75 cd |..0...A..|.cw.u.| +00000290 82 a5 75 15 08 09 e8 6d e9 ba 07 1f f9 9c 24 a5 |..u....m......$.| +000002a0 30 08 d0 51 3b d1 82 14 14 dd 5a 5d c9 2d 91 6f |0..Q;.....Z].-.o| +000002b0 b3 92 30 f1 38 36 e8 34 9e 99 50 a0 c4 29 04 ef |..0.86.4..P..)..| +000002c0 97 f3 cd dc be 22 86 b9 02 41 6a dd 3a 57 5b 61 |....."...Aj.:W[a| +000002d0 ff 68 7d 1e 5e bb 67 5f 76 44 7c f2 f2 03 95 f2 |.h}.^.g_vD|.....| +000002e0 e0 1a 53 70 ce b0 fa cc 7a f3 9a e3 2f 37 a3 cf |..Sp....z.../7..| +000002f0 b5 ca 1d fb fe a3 0d e2 d6 c1 d2 7d 48 80 5b 82 |...........}H.[.| +00000300 56 29 1b b7 43 2e b3 38 19 39 49 16 03 01 00 04 |V)..C..8.9I.....| +00000310 0e 00 00 00 |....| >>> Flow 3 (client to server) -00000000 16 03 01 00 25 10 00 00 21 20 ec f2 2d ca 02 ce |....%...! ..-...| -00000010 11 2d eb 26 d7 d9 fc b2 a7 2d 34 5b a9 3a 0b 2f |.-.&.....-4[.:./| -00000020 5c 49 a9 69 1a 3a 83 90 ec 5f 14 03 01 00 01 01 |\I.i.:..._......| -00000030 16 03 01 00 30 9f 06 c7 a7 a0 c3 a5 3d 60 6e fb |....0.......=`n.| -00000040 c6 18 a4 d2 80 2e ad 8f cf 92 84 94 36 f8 81 28 |............6..(| -00000050 c5 3f 37 e8 d6 e7 6d a3 f5 32 63 a0 ab 7a db 12 |.?7...m..2c..z..| -00000060 17 e1 e4 33 d6 |...3.| +00000000 16 03 01 00 25 10 00 00 21 20 82 03 ad 10 45 0a |....%...! ....E.| +00000010 b9 a4 85 0d 88 bb 9e 16 f1 6c 6a 17 c0 11 09 48 |.........lj....H| +00000020 b4 8b 27 4e 3a 45 a1 b7 a2 03 14 03 01 00 01 01 |..'N:E..........| +00000030 16 03 01 00 30 33 5d a1 85 df 96 6d cf a1 b3 c4 |....03]....m....| +00000040 3f 3c 40 aa 05 25 af 62 ee e9 ce 48 ba e8 08 88 |?<@..%.b...H....| +00000050 95 77 c7 f1 87 c6 ce 46 a2 50 2f 41 3c 8f bf 1a |.w.....F.P/A<...| +00000060 1e 1e 1b 39 9c |...9.| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 18 29 35 d7 c5 |..........0.)5..| -00000010 a2 31 3b 26 85 de 50 26 39 4d 16 22 58 a2 17 bd |.1;&..P&9M."X...| -00000020 4b 73 33 8d dc 3f 92 20 f2 ca 22 00 f5 31 db a7 |Ks3..?. .."..1..| -00000030 18 79 fc 71 87 68 a5 1d a6 db 33 17 03 01 00 20 |.y.q.h....3.... | -00000040 0d be 57 e4 12 6d 2d 3a 33 24 a0 0c c4 9b 27 09 |..W..m-:3$....'.| -00000050 85 e0 0e 42 04 79 21 9a bf 47 fa 0b 38 1a ce 8f |...B.y!..G..8...| -00000060 17 03 01 00 30 6d 27 f1 9b cf 55 4d 65 48 38 1b |....0m'...UMeH8.| -00000070 d9 dd 1d 5b 81 2f 10 a5 65 28 83 93 b3 b1 3a 72 |...[./..e(....:r| -00000080 f0 15 9a e5 9f 21 80 f1 59 a5 0e f1 0c 2b d1 0c |.....!..Y....+..| -00000090 d4 27 73 f3 7e 15 03 01 00 20 6f 08 27 3a d2 60 |.'s.~.... o.':.`| -000000a0 c3 27 bc 73 55 bb 43 53 e2 e0 87 16 ca 8f 49 f0 |.'.sU.CS......I.| -000000b0 88 a8 20 30 9d 42 86 d9 c3 36 |.. 0.B...6| +00000000 14 03 01 00 01 01 16 03 01 00 30 7b 30 af df 92 |..........0{0...| +00000010 2b ee 4d 02 e3 6c 6f 8b 72 32 16 0e 4d ba 71 0d |+.M..lo.r2..M.q.| +00000020 86 0d f5 7d fe dd 07 05 3d fe 70 9b 7f d9 2b c6 |...}....=.p...+.| +00000030 7e 04 82 5f ef 0c 0b c1 e7 a5 18 17 03 01 00 20 |~.._........... | +00000040 ad bd 43 a6 10 e8 e2 41 39 35 69 af a0 00 5f 81 |..C....A95i..._.| +00000050 1e 0a 5e 78 45 2f 66 27 cb 4f db 06 22 c0 ea 0f |..^xE/f'.O.."...| +00000060 17 03 01 00 30 16 69 7f fa 1c 89 36 9f 99 c6 49 |....0.i....6...I| +00000070 e6 0d 9a b7 81 00 75 f5 2d cc 89 e8 be 47 64 76 |......u.-....Gdv| +00000080 ef 34 27 a2 46 bd 8c 14 5b 15 67 ab f1 d9 30 c3 |.4'.F...[.g...0.| +00000090 df 96 a1 59 17 15 03 01 00 20 77 ea 6f e2 ae 81 |...Y..... w.o...| +000000a0 80 4f 37 7b ee 37 3f 40 df a3 e4 be 80 1e 3e 83 |.O7{.7?@......>.| +000000b0 9b 42 f7 95 50 af ab a5 60 54 |.B..P...`T| diff --git a/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/testdata/Server-TLSv12-ECDHE-ECDSA-AES index 697b810..f0d266b 100644 --- a/testdata/Server-TLSv12-ECDHE-ECDSA-AES +++ b/testdata/Server-TLSv12-ECDHE-ECDSA-AES @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 85 01 00 00 81 03 03 83 21 a6 e4 ea |............!...| -00000010 e9 7b 3a 7c 72 28 ee 68 c5 c7 fa f1 98 ed 4a be |.{:|r(.h......J.| -00000020 b8 42 13 fb d3 ab 63 16 d2 74 c8 00 00 04 c0 0a |.B....c..t......| +00000000 16 03 01 00 85 01 00 00 81 03 03 19 8a e1 c7 50 |...............P| +00000010 ba 63 15 9b d5 85 f1 8c 55 43 d3 ce 9c d6 35 20 |.c......UC....5 | +00000020 f3 49 3d 55 a5 11 57 6d db 42 1d 00 00 04 c0 0a |.I=U..Wm.B......| 00000030 00 ff 01 00 00 54 00 0b 00 04 03 00 01 02 00 0a |.....T..........| 00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................| 00000050 00 00 00 17 00 00 00 0d 00 30 00 2e 04 03 05 03 |.........0......| @@ -46,39 +46,39 @@ 00000220 c1 33 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 |.3.......7z..z..| 00000230 2e dd d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 |....i..|V..1x+..| 00000240 78 0d ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 |x.....N6$1{j.9..| -00000250 07 8f 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 |..*............ | +00000250 07 8f 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 |..*............ | 00000260 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 |/.}.G.bC.(.._.).| 00000270 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |0.........._X.;t| -00000280 04 03 00 8b 30 81 88 02 42 00 b9 39 44 59 12 77 |....0...B..9DY.w| -00000290 8d e2 79 25 01 d1 6a 05 3d 53 ea f3 91 d6 c5 09 |..y%..j.=S......| -000002a0 24 bd 0c ad 24 cc 1c a7 fb 03 eb 0a 0d f4 30 96 |$...$.........0.| -000002b0 8d 28 a1 b3 64 ba 30 27 95 29 23 22 91 62 c3 1f |.(..d.0'.)#".b..| -000002c0 51 aa c8 be 17 85 31 8e f5 40 3e 02 42 00 ee a1 |Q.....1..@>.B...| -000002d0 64 14 a1 52 b3 e5 54 c9 24 53 94 5a 43 d8 4f 79 |d..R..T.$S.ZC.Oy| -000002e0 69 4b a8 51 ee de b3 b0 f7 1a 57 a3 28 72 d2 13 |iK.Q......W.(r..| -000002f0 a6 d3 17 0b c4 45 34 7f 10 3b 81 cb 0c 8d 51 b6 |.....E4..;....Q.| -00000300 0b 86 21 d0 ee 1d 7e 73 6b ea 77 8c 66 dc 65 16 |..!...~sk.w.f.e.| -00000310 03 03 00 04 0e 00 00 00 |........| +00000280 04 03 00 8a 30 81 87 02 42 01 f2 09 77 4a e7 f5 |....0...B...wJ..| +00000290 a8 35 3b dd 9d 62 5a 07 97 1e 76 93 b6 07 21 3e |.5;..bZ...v...!>| +000002a0 c8 fd 99 35 50 8a 8b ad e5 de 03 07 c8 5e fe 03 |...5P........^..| +000002b0 c1 99 04 ad 53 b6 76 67 eb 04 99 54 11 4d 4d e9 |....S.vg...T.MM.| +000002c0 74 3f 89 6e d9 c8 02 98 c5 3c cf 02 41 4e 64 21 |t?.n.....<..ANd!| +000002d0 1a 01 5f 2e 89 17 cc 65 33 d0 59 ed 17 59 c4 43 |.._....e3.Y..Y.C| +000002e0 0a fc 68 30 9c e2 c3 86 fb 2a c1 4a ae 32 ef 1d |..h0.....*.J.2..| +000002f0 06 27 36 7d d5 cd 68 23 4c e9 7e 64 b8 eb 42 05 |.'6}..h#L.~d..B.| +00000300 ef 83 36 b2 9e a7 ae 1a cd b0 3a 17 3a 46 16 03 |..6.......:.:F..| +00000310 03 00 04 0e 00 00 00 |.......| >>> Flow 3 (client to server) -00000000 16 03 03 00 25 10 00 00 21 20 ed 3e ba a7 43 53 |....%...! .>..CS| -00000010 5e e4 60 aa 31 3f e1 69 60 32 25 3d fd 8b 32 da |^.`.1?.i`2%=..2.| -00000020 f2 c5 db c7 02 e6 4d d0 de 15 14 03 03 00 01 01 |......M.........| -00000030 16 03 03 00 40 ee 28 f2 27 82 24 9d 17 d1 48 7a |....@.(.'.$...Hz| -00000040 74 2d dd 16 18 b7 70 97 2f 2b 91 47 eb c2 1d ae |t-....p./+.G....| -00000050 3f 48 52 cd ff e7 9e 0b 35 ad 1f 60 5e 07 b1 5e |?HR.....5..`^..^| -00000060 1c ba 6a 85 bb 6b 30 94 41 8a 59 81 cf 37 5f 26 |..j..k0.A.Y..7_&| -00000070 b1 52 36 5f df |.R6_.| +00000000 16 03 03 00 25 10 00 00 21 20 73 43 c2 08 92 f5 |....%...! sC....| +00000010 db bf 2f 8a eb 49 55 f7 5d 6b 80 64 f7 d9 75 1f |../..IU.]k.d..u.| +00000020 67 f6 35 21 3c 95 3f 1c 04 1a 14 03 03 00 01 01 |g.5!<.?.........| +00000030 16 03 03 00 40 59 bb 5a 5d 76 73 a5 30 0e 29 d3 |....@Y.Z]vs.0.).| +00000040 17 d8 2f 30 e6 ed 02 c6 83 12 44 42 d8 79 86 e0 |../0......DB.y..| +00000050 78 7b 43 8d 5b 7c 85 42 fb 7c 67 b0 d0 71 03 0e |x{C.[|.B.|g..q..| +00000060 d0 6b b6 06 f1 16 72 c0 16 66 cf 53 df ae 62 3b |.k....r..f.S..b;| +00000070 f3 57 52 4d 08 |.WRM.| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| -00000010 00 00 00 00 00 00 00 00 00 00 00 f5 05 5a a6 22 |.............Z."| -00000020 90 4e 8d d9 f1 55 c4 78 f2 ec 9d 97 cd fe af ae |.N...U.x........| -00000030 b7 62 00 67 2e b2 d9 1e 0c a3 c8 6a bf d2 3c 42 |.b.g.......j..u......| +00000080 cd 14 5b 4b 0a 7b a2 e6 54 b3 bd 3c f0 eb ca 78 |..[K.{..T..<...x| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 13 3e 42 a5 61 84 ae 49 8b b9 91 |......>B.a..I...| -000000b0 c2 a3 76 74 1e 4f 53 0a fc 71 de 0d d2 44 c8 ac |..vt.OS..q...D..| -000000c0 2e 09 27 e6 ad |..'..| +000000a0 00 00 00 00 00 e6 4b 35 cc 69 58 89 49 67 99 f4 |......K5.iX.Ig..| +000000b0 c2 14 2a bb e7 21 2b fe fe b5 60 ae b2 2a 96 15 |..*..!+...`..*..| +000000c0 e0 65 d2 54 0b |.e.T.| diff --git a/testdata/Server-TLSv13-ECDHE-ECDSA-AES b/testdata/Server-TLSv13-ECDHE-ECDSA-AES index d2ed2ee..d80662d 100644 --- a/testdata/Server-TLSv13-ECDHE-ECDSA-AES +++ b/testdata/Server-TLSv13-ECDHE-ECDSA-AES @@ -1,93 +1,93 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 ca 01 00 00 c6 03 03 be 5b 8c 08 2b |............[..+| -00000010 26 a0 41 0f e3 4e b6 5c 9f 5d 53 04 67 4a 1d a2 |&.A..N.\.]S.gJ..| -00000020 26 3b 83 ab b4 7b c6 ec f8 a6 41 20 a6 de ad e2 |&;...{....A ....| -00000030 0c fd 02 99 11 51 c6 be e8 52 df 0b e2 b3 6f fe |.....Q...R....o.| -00000040 33 3e 2f 90 ac d2 e8 a2 53 8b d9 05 00 04 13 01 |3>/.....S.......| +00000000 16 03 01 00 ca 01 00 00 c6 03 03 1d 95 21 d3 93 |.............!..| +00000010 6b 69 ad 44 69 28 2d 2e 74 c3 77 24 86 82 52 91 |ki.Di(-.t.w$..R.| +00000020 a8 15 64 82 15 2e 02 f8 41 3d c5 20 87 ff 55 4c |..d.....A=. ..UL| +00000030 00 16 80 c2 f7 44 15 18 bc 00 81 d8 7b d8 2c 88 |.....D......{.,.| +00000040 cb 19 31 89 23 d0 82 be d8 7f a4 26 00 04 13 01 |..1.#......&....| 00000050 00 ff 01 00 00 79 00 0b 00 04 03 00 01 02 00 0a |.....y..........| 00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................| 00000070 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 03 |................| 00000080 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................| 00000090 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 04 00 |.........+......| -000000a0 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 20 31 |-.....3.&.$... 1| -000000b0 8e dd f4 7c cf 22 04 c1 c3 04 5c 24 49 db ae ab |...|."....\$I...| -000000c0 0a d0 42 e8 70 51 c7 4f 88 e2 4e 2e 0b 80 65 |..B.pQ.O..N...e| +000000a0 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 20 8d |-.....3.&.$... .| +000000b0 18 6e 7e 5a 97 58 25 0d 07 9e af 9c 9b bd 6f 92 |.n~Z.X%.......o.| +000000c0 e9 08 8f 92 55 28 d2 90 3f fe bc dd db b7 00 |....U(..?......| >>> Flow 2 (server to client) 00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 20 a6 de ad e2 |........... ....| -00000030 0c fd 02 99 11 51 c6 be e8 52 df 0b e2 b3 6f fe |.....Q...R....o.| -00000040 33 3e 2f 90 ac d2 e8 a2 53 8b d9 05 13 01 00 00 |3>/.....S.......| +00000020 00 00 00 00 00 00 00 00 00 00 00 20 87 ff 55 4c |........... ..UL| +00000030 00 16 80 c2 f7 44 15 18 bc 00 81 d8 7b d8 2c 88 |.....D......{.,.| +00000040 cb 19 31 89 23 d0 82 be d8 7f a4 26 13 01 00 00 |..1.#......&....| 00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /| 00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0| 00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.| -00000080 03 03 00 01 01 17 03 03 00 17 cc d0 60 a1 dc d6 |............`...| -00000090 46 57 69 3d df 0e 0f 7f a8 34 2d 87 71 84 16 54 |FWi=.....4-.q..T| -000000a0 9d 17 03 03 02 22 cb 9c f9 3e a0 fd bf 07 03 7c |....."...>.....|| -000000b0 53 0c 15 22 0b 78 e5 02 36 e6 e7 6c 5b f9 aa 8d |S..".x..6..l[...| -000000c0 54 8e b1 15 d4 23 05 12 5e 6e 0f 0f 65 77 bf b5 |T....#..^n..ew..| -000000d0 32 28 0e 32 ca 9f 61 c3 37 23 87 e8 ec 19 1d ba |2(.2..a.7#......| -000000e0 ef f5 18 eb ba 49 2d 86 a6 d1 f7 c1 9e 67 10 9f |.....I-......g..| -000000f0 a1 d2 62 bd 4c 6c 5e a4 41 f6 1e fa fd e7 55 bc |..b.Ll^.A.....U.| -00000100 16 ad 91 91 de 03 86 d7 e1 88 87 ab 0e f4 f5 bb |................| -00000110 16 da 37 bb a4 ce 4e 6c 5f 88 41 f9 a2 90 9a 2d |..7...Nl_.A....-| -00000120 5c 14 d5 01 28 06 a9 20 a4 ae 92 17 c5 95 b1 dc |\...(.. ........| -00000130 02 a8 3f 3b a7 97 91 5a 4f 56 bb db b6 30 0d 80 |..?;...ZOV...0..| -00000140 35 ac 91 6f 4f ba 1e 10 c6 fc d2 ca 96 e4 9d 1f |5..oO...........| -00000150 2f 29 00 3a 11 b7 77 dd d5 ed 76 9f 67 a1 b1 0c |/).:..w...v.g...| -00000160 5d 34 34 eb 42 49 23 15 49 12 24 24 73 be a9 65 |]44.BI#.I.$$s..e| -00000170 99 b6 b4 3f 18 0c d1 32 26 eb 86 93 5c 0e e8 06 |...?...2&...\...| -00000180 fb d7 9f 0e d9 26 14 47 b8 e5 67 8c c8 cb 0c 55 |.....&.G..g....U| -00000190 61 70 a9 ce 0d 4e bf ca 40 9c e7 0d 2b 5d 54 b7 |ap...N..@...+]T.| -000001a0 5a 64 50 e6 a1 c9 fc 47 7d e7 0a 13 36 8d 70 eb |ZdP....G}...6.p.| -000001b0 68 65 e4 9b 9d 12 d1 d9 0d 32 72 59 0f 46 b2 e2 |he.......2rY.F..| -000001c0 21 ab 13 d4 ab f3 6e b6 44 16 b8 85 bb dc f4 f7 |!.....n.D.......| -000001d0 d6 ce 5c 9f c0 4c 28 8f 36 39 ec 29 c7 33 bd ea |..\..L(.69.).3..| -000001e0 2d 10 16 84 50 c5 18 5b 2c a3 99 bb 3b 0b 70 66 |-...P..[,...;.pf| -000001f0 72 9a 83 01 06 2a bf 4a 60 c5 5d 41 a1 f0 92 bb |r....*.J`.]A....| -00000200 3b 2a 1a 41 3a 57 c3 22 13 2c b4 7b 3e 47 52 ea |;*.A:W.".,.{>GR.| -00000210 79 8a bf ef 2e 2c f7 89 c7 36 5a df 38 c2 04 b6 |y....,...6Z.8...| -00000220 6f 96 cd 7c 01 b3 e3 cd 4a 83 56 40 06 58 8a 7c |o..|....J.V@.X.|| -00000230 8c 75 df b6 b8 76 63 71 89 72 0a 64 de 23 7d 50 |.u...vcq.r.d.#}P| -00000240 77 a8 f6 a0 81 9d e9 ed 81 5e 20 c8 9f 65 3c 95 |w........^ ..e<.| -00000250 cf ed 99 80 71 06 5e 00 46 0d 0c 22 b3 88 f0 c5 |....q.^.F.."....| -00000260 33 3e 13 6b f2 07 9c db 20 31 9c 8d ea d7 73 e8 |3>.k.... 1....s.| -00000270 00 e1 2b f4 c8 d7 34 37 4a 98 b9 4d 28 db 15 8a |..+...47J..M(...| -00000280 af 53 14 3b 02 54 a3 0b 5f 10 ff 5d 20 1c 19 ae |.S.;.T.._..] ...| -00000290 6b 8a 99 a5 8f e0 ac dd c1 ba 1f 85 56 a3 94 bc |k...........V...| -000002a0 79 03 5f d5 dd e1 8e 62 b7 82 fa 92 c3 d5 8a fc |y._....b........| -000002b0 6b 17 24 d9 af db 3d 9c 0f 51 82 3d a2 ec 5f 9c |k.$...=..Q.=.._.| -000002c0 dc 69 a5 ce db d8 8b 87 17 03 03 00 a3 69 cd 7b |.i...........i.{| -000002d0 9f ac ad 72 11 b2 5d ee 19 63 d0 35 12 6d 5e 3f |...r..]..c.5.m^?| -000002e0 81 a8 18 4a d4 09 f3 80 38 4a 31 08 3e a0 4c 78 |...J....8J1.>.Lx| -000002f0 48 08 e9 90 ba e7 2a b4 73 2e 2b 2b 15 60 ce 09 |H.....*.s.++.`..| -00000300 7d df 49 31 e1 9d ff 92 1d b4 af 2e 8c f8 a6 2e |}.I1............| -00000310 93 d7 b9 10 69 10 7f 04 0d 8d e2 37 09 a7 d0 2a |....i......7...*| -00000320 ac ea 51 49 50 1d 1c 54 7f b9 15 ad 8c 77 ef 1d |..QIP..T.....w..| -00000330 a6 59 a3 bf b2 53 f7 6c 21 92 e0 36 c5 0d 61 94 |.Y...S.l!..6..a.| -00000340 be 61 5e 77 25 35 df e4 5f 67 c1 c6 af 51 e4 ce |.a^w%5.._g...Q..| -00000350 c4 28 c5 4e bc f6 c6 ba 32 dc 8e c7 45 f3 4d a1 |.(.N....2...E.M.| -00000360 70 53 98 46 8f 39 c2 cc b7 fc f7 24 11 97 72 b3 |pS.F.9.....$..r.| -00000370 17 03 03 00 35 76 be b6 7a 3f e3 08 7a a2 65 25 |....5v..z?..z.e%| -00000380 fd 0b c3 87 be ba eb ca cb 3d c1 25 10 e0 7b 00 |.........=.%..{.| -00000390 37 7a 52 9e d6 b2 e7 ba 8e 51 de 15 c4 e8 16 eb |7zR......Q......| -000003a0 c6 21 92 42 b1 62 f4 ce 27 ba 17 03 03 00 8b 54 |.!.B.b..'......T| -000003b0 03 de d7 a7 85 2f 4b 23 2d d5 3a b4 3d 3d f6 00 |...../K#-.:.==..| -000003c0 ac ab bd 6f dd bf 9f 24 fb 1b d4 01 39 3e c0 87 |...o...$....9>..| -000003d0 bb 32 ca f6 61 b2 ef 5d 9c 2c 1b a5 10 66 7b fd |.2..a..].,...f{.| -000003e0 4b d0 03 dc 53 a9 0d 5a d5 c4 4c 25 9c 55 e6 f8 |K...S..Z..L%.U..| -000003f0 d1 d8 49 dc 36 a1 92 ae f1 3e 2f 11 66 87 93 69 |..I.6....>/.f..i| -00000400 24 2e 5d 6c f6 79 15 68 a8 99 2e 1a 9c e2 85 4e |$.]l.y.h.......N| -00000410 5f d6 a8 3c 70 e1 67 cb df b2 1b ab 2b ed dc b6 |_....b...O| +000000a0 e8 17 03 03 02 22 3f 87 53 63 dc 59 f7 32 60 4b |....."?.Sc.Y.2`K| +000000b0 bd 9f e1 fc 4c 9a 98 18 94 e1 c1 07 ab 11 33 dc |....L.........3.| +000000c0 f1 48 67 e6 66 83 3c 88 53 c7 dc af e2 87 bc 0b |.Hg.f.<.S.......| +000000d0 d7 60 99 83 29 a1 1c 30 09 ba 4a e1 a9 c2 0e 34 |.`..)..0..J....4| +000000e0 cb a6 f2 8b 1b a0 b0 e6 21 27 3d b8 b4 90 0c 61 |........!'=....a| +000000f0 af 38 db fe fe 9c 34 09 1e 1a c8 f2 e9 05 68 ee |.8....4.......h.| +00000100 9c ec 74 b8 10 25 29 3d 52 71 87 c6 88 22 5a e9 |..t..%)=Rq..."Z.| +00000110 33 d0 d3 75 a8 94 b2 6d 48 4f 63 d1 32 f2 a3 70 |3..u...mHOc.2..p| +00000120 f1 a5 0b 4c 5d 7c 91 9b 04 d4 c3 9e 37 dd 67 a1 |...L]|......7.g.| +00000130 aa 23 6f 2b d0 42 b9 30 5c ed ae 12 36 f1 7c b3 |.#o+.B.0\...6.|.| +00000140 92 de 02 3a 99 c3 98 91 a3 09 43 ef 24 8d 67 e7 |...:......C.$.g.| +00000150 0d 68 22 e1 cc 99 8e 8e 64 09 be 50 f7 4a 37 0a |.h".....d..P.J7.| +00000160 02 af 88 db 8b a0 68 0d 7e 97 d9 9c 48 c3 bd aa |......h.~...H...| +00000170 db 01 69 2b 2b e6 f5 4b 66 c0 7a 8c fe 4d 8f 7b |..i++..Kf.z..M.{| +00000180 94 be 58 b5 44 67 df 26 3f 79 ee 55 bf bf aa 52 |..X.Dg.&?y.U...R| +00000190 95 ec 6b 7f 2b 68 f0 5a 81 4e 13 25 91 bd 9a df |..k.+h.Z.N.%....| +000001a0 dd 2c ae 6d c3 47 27 c2 3f 51 98 a3 b7 06 ec 2f |.,.m.G'.?Q...../| +000001b0 d6 c0 7f 1f e5 5e 3c 50 d3 6e 82 33 be 07 48 0b |.....^..}.....HUB..| +00000260 d0 b2 8e 4d c6 26 bb 77 9e 3f e0 0a 90 a4 3b eb |...M.&.w.?....;.| +00000270 37 94 c4 e8 39 12 82 24 b3 8b 6d 0d ed 9c 31 f0 |7...9..$..m...1.| +00000280 d0 5a cb b0 79 9b d2 ed ab 08 8b 9d ad 25 7a ce |.Z..y........%z.| +00000290 d7 6d c8 11 0a 60 f4 81 e9 e3 e3 42 7b 3d 95 67 |.m...`.....B{=.g| +000002a0 c2 4e 3e 80 11 2e 09 53 94 03 c0 88 cb 23 7e d2 |.N>....S.....#~.| +000002b0 ad e2 dc e7 e2 0b ba 74 9c 04 ad 75 e6 7f 5a fb |.......t...u..Z.| +000002c0 53 5a 98 14 18 4f 1d 2b 17 03 03 00 a4 7a ce c7 |SZ...O.+.....z..| +000002d0 9c de bc 27 04 f7 8b 4b a1 73 7d 0d fa b5 a1 e2 |...'...K.s}.....| +000002e0 fe 8b 33 8d 48 64 65 13 68 e2 5d e2 d7 3e 67 f2 |..3.Hde.h.]..>g.| +000002f0 db bd ff f9 e5 3e 4c b1 56 e3 22 95 88 23 48 fe |.....>L.V."..#H.| +00000300 0f 80 4c 5c 1c 74 0e 26 d4 7c 17 83 65 d6 a3 51 |..L\.t.&.|..e..Q| +00000310 5a 01 a5 12 9c db 0b c9 0b 8b 53 c7 03 75 b9 04 |Z.........S..u..| +00000320 a0 62 df 11 75 ae ff 33 7b 98 6b 7b 35 3e 41 4c |.b..u..3{.k{5>AL| +00000330 9b 16 12 b4 39 ce 9a d5 e9 83 78 b3 4b 3e d6 82 |....9.....x.K>..| +00000340 75 66 bf 73 e4 26 e6 22 8e 2f fe 4d 49 e4 b5 03 |uf.s.&."./.MI...| +00000350 04 a6 65 59 c2 aa e2 e6 ec f0 e2 99 b5 c4 55 75 |..eY..........Uu| +00000360 e1 90 a4 73 cb 21 78 df 4e 96 e2 99 75 15 77 59 |...s.!x.N...u.wY| +00000370 db 17 03 03 00 35 bc 1c 15 d7 b0 62 21 d4 dd 09 |.....5.....b!...| +00000380 1d aa 05 3c e3 ea 0a 9d 89 1f aa 2f f7 75 93 86 |...<......./.u..| +00000390 35 ee 5f 06 20 99 17 ca 4c 05 65 07 f7 56 9f 62 |5._. ...L.e..V.b| +000003a0 2a ea e2 05 f0 be fe bf d6 09 46 17 03 03 00 8b |*.........F.....| +000003b0 37 1a 6c e5 ea 27 e7 b2 d7 87 9a 1a a1 41 b5 64 |7.l..'.......A.d| +000003c0 61 8b bb 1c 64 a2 37 de 39 b3 5b f4 5b 9f bf d8 |a...d.7.9.[.[...| +000003d0 e7 3d be ad 96 6c 69 19 ce 8e a8 12 14 5d 1e 79 |.=...li......].y| +000003e0 c5 12 53 c3 13 81 5a 22 44 e5 6e c4 97 cc 18 19 |..S...Z"D.n.....| +000003f0 c4 04 08 cf 16 dd df 3d 4f 13 40 5f 33 38 f5 0f |.......=O.@_38..| +00000400 4f bb 41 e2 85 85 43 de d0 b5 7a 61 d8 3a 53 41 |O.A...C...za.:SA| +00000410 d2 ad 7b e4 bf 02 d2 14 7d f7 0c 05 b8 bb 21 90 |..{.....}.....!.| +00000420 a5 61 76 7e 07 5d bf e2 a1 f8 1a a6 77 42 2a 7c |.av~.]......wB*|| +00000430 7a 41 a7 5e 04 c2 49 02 45 a8 f5 |zA.^..I.E..| >>> Flow 3 (client to server) -00000000 14 03 03 00 01 01 17 03 03 00 35 46 8b fa 42 0d |..........5F..B.| -00000010 fa 3e 9e 80 76 12 ce 73 ae 85 67 ee af 1e 25 6e |.>..v..s..g...%n| -00000020 0b 46 4c bd 5a 46 8e 5c 27 7a 0a 8d d3 9c 3c 29 |.FL.ZF.\'z....<)| -00000030 4c c8 08 78 ac 9f f4 7a 38 8d 49 6a 01 b6 f5 83 |L..x...z8.Ij....| +00000000 14 03 03 00 01 01 17 03 03 00 35 3d f2 27 fe 81 |..........5=.'..| +00000010 4c 6e 61 1f 34 f8 3d 25 1f 33 d6 22 aa 7f ab 08 |Lna.4.=%.3."....| +00000020 2c 48 44 39 74 2c e9 be 78 7f c7 db 27 b0 b0 6d |,HD9t,..x...'..m| +00000030 b2 8b 87 6c e5 5c 38 79 9f ed 3d 4f 92 81 dc ea |...l.\8y..=O....| >>> Flow 4 (server to client) -00000000 17 03 03 00 1e c2 1a dc 0a cb 9a 11 f7 a1 c2 1f |................| -00000010 54 7d 32 6f 0e 13 b6 6b 9f e1 c6 14 63 fc 18 b9 |T}2o...k....c...| -00000020 81 53 44 17 03 03 00 13 c9 72 ae 5e 2b c1 6f 64 |.SD......r.^+.od| -00000030 e0 70 47 15 b1 ec c3 25 00 7f 4e |.pG....%..N| +00000000 17 03 03 00 1e f7 99 f9 d8 a2 00 d9 e3 48 d9 b2 |.............H..| +00000010 35 37 93 6f b0 1f d5 81 b1 16 b1 e4 d8 b4 40 ce |57.o..........@.| +00000020 97 9f 16 17 03 03 00 13 a4 cb 62 61 70 e9 67 c3 |..........bap.g.| +00000030 21 02 19 bc 01 01 5d 9b 15 d4 84 |!.....]....| From 7e4b8b87ca27aeade2fa71de41737ca2a82ffd92 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sun, 17 Nov 2024 12:04:24 +0100 Subject: [PATCH 18/34] crypto: centralize external test module fetches This has the important advantage of using the system GOMODCACHE when it exists, avoiding the download on every "go test". While at it, also consistently use testenv.Command. Change-Id: Ic999ffa281f6da73fe601b0feba29e60982cce3d Reviewed-on: https://go-review.googlesource.com/c/go/+/628755 Reviewed-by: Russ Cox Auto-Submit: Filippo Valsorda TryBot-Bypass: Filippo Valsorda Reviewed-by: Dmitri Shuralyov --- bogo_shim_test.go | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/bogo_shim_test.go b/bogo_shim_test.go index ff836d9..a3bf116 100644 --- a/bogo_shim_test.go +++ b/bogo_shim_test.go @@ -2,6 +2,7 @@ package tls import ( "bytes" + "crypto/internal/cryptotest" "crypto/x509" "encoding/base64" "encoding/json" @@ -14,7 +15,6 @@ import ( "log" "net" "os" - "os/exec" "path/filepath" "runtime" "slices" @@ -370,11 +370,6 @@ func bogoShim() { } func TestBogoSuite(t *testing.T) { - testenv.SkipIfShortAndSlow(t) - testenv.MustHaveExternalNetwork(t) - testenv.MustHaveGoRun(t) - testenv.MustHaveExec(t) - if testing.Short() { t.Skip("skipping in short mode") } @@ -395,17 +390,7 @@ func TestBogoSuite(t *testing.T) { bogoDir = *bogoLocalDir } else { const boringsslModVer = "v0.0.0-20240523173554-273a920f84e8" - output, err := exec.Command("go", "mod", "download", "-json", "boringssl.googlesource.com/boringssl.git@"+boringsslModVer).CombinedOutput() - if err != nil { - t.Fatalf("failed to download boringssl: %s", err) - } - var j struct { - Dir string - } - if err := json.Unmarshal(output, &j); err != nil { - t.Fatalf("failed to parse 'go mod download' output: %s", err) - } - bogoDir = j.Dir + bogoDir = cryptotest.FetchModule(t, "boringssl.googlesource.com/boringssl.git", boringsslModVer) } cwd, err := os.Getwd() @@ -429,11 +414,7 @@ func TestBogoSuite(t *testing.T) { args = append(args, fmt.Sprintf("-test=%s", *bogoFilter)) } - goCmd, err := testenv.GoTool() - if err != nil { - t.Fatal(err) - } - cmd := exec.Command(goCmd, args...) + cmd := testenv.Command(t, testenv.GoToolPath(t), args...) out := &strings.Builder{} cmd.Stderr = out cmd.Dir = filepath.Join(bogoDir, "ssl/test/runner") From 0d5c2fe3a17debafa0fff48fa754ebb6b45ac9c0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 20 Nov 2024 09:03:35 -0500 Subject: [PATCH 19/34] all: rename crypto/internal/fips to crypto/internal/fips140 Sometimes we've used the 140 suffix (GOFIPS140, crypto/fips140) and sometimes not (crypto/internal/fips, cmd/go/internal/fips). Use it always, to avoid having to remember which is which. Also, there are other FIPS standards, like AES (FIPS 197), SHA-2 (FIPS 180), and so on, which have nothing to do with FIPS 140. Best to be clear. For #70123. Change-Id: I33b29dabd9e8b2703d2af25e428f88bc81c7c307 Reviewed-on: https://go-review.googlesource.com/c/go/+/630115 Reviewed-by: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Auto-Submit: Russ Cox Reviewed-by: Roland Shoemaker --- cipher_suites.go | 6 +++--- handshake_client.go | 4 ++-- handshake_client_tls13.go | 6 +++--- handshake_server_tls13.go | 4 ++-- key_schedule.go | 6 +++--- key_schedule_test.go | 4 ++-- prf.go | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cipher_suites.go b/cipher_suites.go index 1c849e3..9e831a9 100644 --- a/cipher_suites.go +++ b/cipher_suites.go @@ -11,8 +11,8 @@ import ( "crypto/des" "crypto/hmac" "crypto/internal/boring" - fipsaes "crypto/internal/fips/aes" - "crypto/internal/fips/aes/gcm" + fipsaes "crypto/internal/fips140/aes" + "crypto/internal/fips140/aes/gcm" "crypto/rc4" "crypto/sha1" "crypto/sha256" @@ -367,7 +367,7 @@ var tdesCiphers = map[uint16]bool{ } var ( - // Keep in sync with crypto/internal/fips/aes/gcm.supportsAESGCM. + // Keep in sync with crypto/internal/fips140/aes/gcm.supportsAESGCM. hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41 && cpu.X86.HasSSSE3 hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCTR && cpu.S390X.HasGHASH diff --git a/handshake_client.go b/handshake_client.go index ea9c4c5..3926ebd 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -10,8 +10,8 @@ import ( "crypto" "crypto/ecdsa" "crypto/ed25519" - "crypto/internal/fips/mlkem" - "crypto/internal/fips/tls13" + "crypto/internal/fips140/mlkem" + "crypto/internal/fips140/tls13" "crypto/internal/hpke" "crypto/rsa" "crypto/subtle" diff --git a/handshake_client_tls13.go b/handshake_client_tls13.go index 6ce83b9..53f1665 100644 --- a/handshake_client_tls13.go +++ b/handshake_client_tls13.go @@ -9,9 +9,9 @@ import ( "context" "crypto" "crypto/hmac" - "crypto/internal/fips/hkdf" - "crypto/internal/fips/mlkem" - "crypto/internal/fips/tls13" + "crypto/internal/fips140/hkdf" + "crypto/internal/fips140/mlkem" + "crypto/internal/fips140/tls13" "crypto/rsa" "crypto/subtle" "errors" diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index aa1ffd9..90c0320 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -9,8 +9,8 @@ import ( "context" "crypto" "crypto/hmac" - "crypto/internal/fips/mlkem" - "crypto/internal/fips/tls13" + "crypto/internal/fips140/mlkem" + "crypto/internal/fips140/tls13" "crypto/rsa" "errors" "hash" diff --git a/key_schedule.go b/key_schedule.go index 99229ea..60527b0 100644 --- a/key_schedule.go +++ b/key_schedule.go @@ -7,9 +7,9 @@ package tls import ( "crypto/ecdh" "crypto/hmac" - "crypto/internal/fips/mlkem" - "crypto/internal/fips/sha3" - "crypto/internal/fips/tls13" + "crypto/internal/fips140/mlkem" + "crypto/internal/fips140/sha3" + "crypto/internal/fips140/tls13" "errors" "hash" "io" diff --git a/key_schedule_test.go b/key_schedule_test.go index 0dc3601..f96b14c 100644 --- a/key_schedule_test.go +++ b/key_schedule_test.go @@ -6,8 +6,8 @@ package tls import ( "bytes" - "crypto/internal/fips/mlkem" - "crypto/internal/fips/tls13" + "crypto/internal/fips140/mlkem" + "crypto/internal/fips140/tls13" "crypto/sha256" "encoding/hex" "strings" diff --git a/prf.go b/prf.go index c306ca4..e736954 100644 --- a/prf.go +++ b/prf.go @@ -7,7 +7,7 @@ package tls import ( "crypto" "crypto/hmac" - "crypto/internal/fips/tls12" + "crypto/internal/fips140/tls12" "crypto/md5" "crypto/sha1" "crypto/sha256" From f37765f45c0babeaba398e33497bf293ecdd3221 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 12 Nov 2024 23:39:27 +0100 Subject: [PATCH 20/34] internal/byteorder: use canonical Go casing in names If Be and Le stand for big-endian and little-endian, then they should be BE and LE. Change-Id: I723e3962b8918da84791783d3c547638f1c9e8a9 Reviewed-on: https://go-review.googlesource.com/c/go/+/627376 Reviewed-by: Robert Griesemer Auto-Submit: Russ Cox LUCI-TryBot-Result: Go LUCI --- bogo_shim_test.go | 2 +- handshake_client.go | 2 +- handshake_client_test.go | 2 +- handshake_server.go | 2 +- handshake_server_tls13.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bogo_shim_test.go b/bogo_shim_test.go index a3bf116..b29fe2c 100644 --- a/bogo_shim_test.go +++ b/bogo_shim_test.go @@ -261,7 +261,7 @@ func bogoShim() { // Write the shim ID we were passed as a little endian uint64 shimIDBytes := make([]byte, 8) - byteorder.LePutUint64(shimIDBytes, *shimID) + byteorder.LEPutUint64(shimIDBytes, *shimID) if _, err := conn.Write(shimIDBytes); err != nil { log.Fatalf("failed to write shim id: %s", err) } diff --git a/handshake_client.go b/handshake_client.go index 3926ebd..be88278 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -714,7 +714,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { return err } if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ { - c.curveID = CurveID(byteorder.BeUint16(skx.key[1:])) + c.curveID = CurveID(byteorder.BEUint16(skx.key[1:])) } msg, err = c.readHandshake(&hs.finishedHash) diff --git a/handshake_client_test.go b/handshake_client_test.go index c001822..2aded1a 100644 --- a/handshake_client_test.go +++ b/handshake_client_test.go @@ -207,7 +207,7 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, var serverInfo bytes.Buffer for _, ext := range test.extensions { pem.Encode(&serverInfo, &pem.Block{ - Type: fmt.Sprintf("SERVERINFO FOR EXTENSION %d", byteorder.BeUint16(ext)), + Type: fmt.Sprintf("SERVERINFO FOR EXTENSION %d", byteorder.BEUint16(ext)), Bytes: ext, }) } diff --git a/handshake_server.go b/handshake_server.go index bc4e51b..740c149 100644 --- a/handshake_server.go +++ b/handshake_server.go @@ -593,7 +593,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { } if skx != nil { if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ { - c.curveID = CurveID(byteorder.BeUint16(skx.key[1:])) + c.curveID = CurveID(byteorder.BEUint16(skx.key[1:])) } if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil { return err diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index 90c0320..c2349ad 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -900,7 +900,7 @@ func (c *Conn) sendSessionTicket(earlyData bool, extra [][]byte) error { if _, err := c.config.rand().Read(ageAdd); err != nil { return err } - m.ageAdd = byteorder.LeUint32(ageAdd) + m.ageAdd = byteorder.LEUint32(ageAdd) if earlyData { // RFC 9001, Section 4.6.1 From f189b9184a35e59cd29598bd7ac176998abab6d1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 21 Nov 2024 08:46:57 -0500 Subject: [PATCH 21/34] internal/copyright: add test that copyright notices exist We shouldn't spend human code review time checking this. Let the computer check. Change-Id: I6de9d733c128d833b958b0e43a52b564e8f82dd3 Reviewed-on: https://go-review.googlesource.com/c/go/+/630417 LUCI-TryBot-Result: Go LUCI Reviewed-by: Sam Thanawalla --- bogo_shim_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bogo_shim_test.go b/bogo_shim_test.go index b29fe2c..bb78c64 100644 --- a/bogo_shim_test.go +++ b/bogo_shim_test.go @@ -1,3 +1,7 @@ +// 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 tls import ( From 9abc9d713203eb573fb0b08776306c9fcc5d4a95 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Mon, 18 Nov 2024 22:18:56 +0100 Subject: [PATCH 22/34] crypto/tls: FIPS 140-3 mode Consolidates handling of FIPS 140-3 considerations for the tls package. Considerations specific to certificates are now handled in tls instead of x509 to limit the area-of-effect of FIPS as much as possible. Boringcrypto specific prefixes are renamed as appropriate. For #69536 Co-authored-by: Filippo Valsorda Change-Id: I1b1fef83c3599e4c9b98ad81db582ac93253030b Reviewed-on: https://go-review.googlesource.com/c/go/+/629675 Reviewed-by: Filippo Valsorda Reviewed-by: Dmitri Shuralyov Reviewed-by: Russ Cox Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: Go LUCI --- auth.go | 3 +- boring.go | 15 ---- common.go | 66 ++++++++++++-- defaults.go | 4 +- boring_test.go => fips_test.go | 156 ++++++++++++++++++--------------- fipsonly/fipsonly.go | 4 +- fipsonly/fipsonly_test.go | 6 +- handshake_client.go | 25 ++++-- handshake_server.go | 11 ++- handshake_server_tls13.go | 3 +- internal/fips140tls/fipstls.go | 37 ++++++++ notboring.go | 9 -- 12 files changed, 220 insertions(+), 119 deletions(-) delete mode 100644 boring.go rename boring_test.go => fips_test.go (81%) create mode 100644 internal/fips140tls/fipstls.go delete mode 100644 notboring.go diff --git a/auth.go b/auth.go index 5bb202c..9e3ce22 100644 --- a/auth.go +++ b/auth.go @@ -11,6 +11,7 @@ import ( "crypto/ed25519" "crypto/elliptic" "crypto/rsa" + "crypto/tls/internal/fips140tls" "errors" "fmt" "hash" @@ -242,7 +243,7 @@ func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureSche // Pick signature scheme in the peer's preference order, as our // preference order is not configurable. for _, preferredAlg := range peerAlgs { - if needFIPS() && !isSupportedSignatureAlgorithm(preferredAlg, defaultSupportedSignatureAlgorithmsFIPS) { + if fips140tls.Required() && !isSupportedSignatureAlgorithm(preferredAlg, defaultSupportedSignatureAlgorithmsFIPS) { continue } if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) { diff --git a/boring.go b/boring.go deleted file mode 100644 index c44ae92..0000000 --- a/boring.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 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. - -//go:build boringcrypto - -package tls - -import "crypto/internal/boring/fipstls" - -// needFIPS returns fipstls.Required(), which is not available without the -// boringcrypto build tag. -func needFIPS() bool { - return fipstls.Required() -} diff --git a/common.go b/common.go index dba9650..662f1fc 100644 --- a/common.go +++ b/common.go @@ -15,6 +15,7 @@ import ( "crypto/rand" "crypto/rsa" "crypto/sha512" + "crypto/tls/internal/fips140tls" "crypto/x509" "errors" "fmt" @@ -1061,12 +1062,12 @@ func (c *Config) time() time.Time { func (c *Config) cipherSuites() []uint16 { if c.CipherSuites == nil { - if needFIPS() { + if fips140tls.Required() { return defaultCipherSuitesFIPS } return defaultCipherSuites() } - if needFIPS() { + if fips140tls.Required() { cipherSuites := slices.Clone(c.CipherSuites) return slices.DeleteFunc(cipherSuites, func(id uint16) bool { return !slices.Contains(defaultCipherSuitesFIPS, id) @@ -1092,7 +1093,7 @@ var tls10server = godebug.New("tls10server") func (c *Config) supportedVersions(isClient bool) []uint16 { versions := make([]uint16, 0, len(supportedVersions)) for _, v := range supportedVersions { - if needFIPS() && !slices.Contains(defaultSupportedVersionsFIPS, v) { + if fips140tls.Required() && !slices.Contains(defaultSupportedVersionsFIPS, v) { continue } if (c == nil || c.MinVersion == 0) && v < VersionTLS12 { @@ -1140,12 +1141,12 @@ func (c *Config) curvePreferences(version uint16) []CurveID { var curvePreferences []CurveID if c != nil && len(c.CurvePreferences) != 0 { curvePreferences = slices.Clone(c.CurvePreferences) - if needFIPS() { + if fips140tls.Required() { return slices.DeleteFunc(curvePreferences, func(c CurveID) bool { return !slices.Contains(defaultCurvePreferencesFIPS, c) }) } - } else if needFIPS() { + } else if fips140tls.Required() { curvePreferences = slices.Clone(defaultCurvePreferencesFIPS) } else { curvePreferences = defaultCurvePreferences() @@ -1617,7 +1618,7 @@ func unexpectedMessageError(wanted, got any) error { // supportedSignatureAlgorithms returns the supported signature algorithms. func supportedSignatureAlgorithms() []SignatureScheme { - if !needFIPS() { + if !fips140tls.Required() { return defaultSupportedSignatureAlgorithms } return defaultSupportedSignatureAlgorithmsFIPS @@ -1646,3 +1647,56 @@ func (e *CertificateVerificationError) Error() string { func (e *CertificateVerificationError) Unwrap() error { return e.Err } + +// fipsAllowedChains returns chains that are allowed to be used in a TLS connection +// based on the current fips140tls enforcement setting. +// +// If fips140tls is not required, the chains are returned as-is with no processing. +// Otherwise, the returned chains are filtered to only those allowed by FIPS 140-3. +// If this results in no chains it returns an error. +func fipsAllowedChains(chains [][]*x509.Certificate) ([][]*x509.Certificate, error) { + if !fips140tls.Required() { + return chains, nil + } + + permittedChains := make([][]*x509.Certificate, 0, len(chains)) + for _, chain := range chains { + if fipsAllowChain(chain) { + permittedChains = append(permittedChains, chain) + } + } + + if len(permittedChains) == 0 { + return nil, errors.New("tls: no FIPS compatible certificate chains found") + } + + return permittedChains, nil +} + +func fipsAllowChain(chain []*x509.Certificate) bool { + if len(chain) == 0 { + return false + } + + for _, cert := range chain { + if !fipsAllowCert(cert) { + return false + } + } + + return true +} + +func fipsAllowCert(c *x509.Certificate) bool { + // The key must be RSA 2048, RSA 3072, RSA 4096, + // or ECDSA P-256, P-384, P-521. + switch k := c.PublicKey.(type) { + case *rsa.PublicKey: + size := k.N.BitLen() + return size == 2048 || size == 3072 || size == 4096 + case *ecdsa.PublicKey: + return k.Curve == elliptic.P256() || k.Curve == elliptic.P384() || k.Curve == elliptic.P521() + } + + return false +} diff --git a/defaults.go b/defaults.go index ad4070d..170c200 100644 --- a/defaults.go +++ b/defaults.go @@ -90,7 +90,9 @@ var defaultCipherSuitesTLS13NoAES = []uint16{ TLS_AES_256_GCM_SHA384, } -// The FIPS-only policies below match BoringSSL's ssl_policy_fips_202205. +// The FIPS-only policies below match BoringSSL's +// ssl_compliance_policy_fips_202205, which is based on NIST SP 800-52r2. +// https://cs.opensource.google/boringssl/boringssl/+/master:ssl/ssl_lib.cc;l=3289;drc=ea7a88fa var defaultSupportedVersionsFIPS = []uint16{ VersionTLS12, diff --git a/boring_test.go b/fips_test.go similarity index 81% rename from boring_test.go rename to fips_test.go index 5605042..b28b6f4 100644 --- a/boring_test.go +++ b/fips_test.go @@ -2,21 +2,20 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build boringcrypto - package tls import ( "crypto/ecdsa" "crypto/elliptic" - "crypto/internal/boring/fipstls" "crypto/rand" "crypto/rsa" + "crypto/tls/internal/fips140tls" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "fmt" "internal/obscuretestdata" + "internal/testenv" "math/big" "net" "runtime" @@ -50,7 +49,7 @@ func generateKeyShare(group CurveID) keyShare { return keyShare{group: group, data: key.PublicKey().Bytes()} } -func TestBoringServerProtocolVersion(t *testing.T) { +func TestFIPSServerProtocolVersion(t *testing.T) { test := func(t *testing.T, name string, v uint16, msg string) { t.Run(name, func(t *testing.T) { serverConfig := testConfig.Clone() @@ -79,9 +78,9 @@ func TestBoringServerProtocolVersion(t *testing.T) { test(t, "VersionTLS12", VersionTLS12, "") test(t, "VersionTLS13", VersionTLS13, "") - t.Run("fipstls", func(t *testing.T) { - fipstls.Force() - defer fipstls.Abandon() + t.Run("fips140tls", func(t *testing.T) { + fips140tls.Force() + defer fips140tls.TestingOnlyAbandon() test(t, "VersionTLS10", VersionTLS10, "supported versions") test(t, "VersionTLS11", VersionTLS11, "supported versions") test(t, "VersionTLS12", VersionTLS12, "") @@ -89,11 +88,11 @@ func TestBoringServerProtocolVersion(t *testing.T) { }) } -func isBoringVersion(v uint16) bool { +func isFIPSVersion(v uint16) bool { return v == VersionTLS12 || v == VersionTLS13 } -func isBoringCipherSuite(id uint16) bool { +func isFIPSCipherSuite(id uint16) bool { switch id { case TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, @@ -106,7 +105,7 @@ func isBoringCipherSuite(id uint16) bool { return false } -func isBoringCurve(id CurveID) bool { +func isFIPSCurve(id CurveID) bool { switch id { case CurveP256, CurveP384: return true @@ -123,7 +122,7 @@ func isECDSA(id uint16) bool { return false // TLS 1.3 cipher suites are not tied to the signature algorithm. } -func isBoringSignatureScheme(alg SignatureScheme) bool { +func isFIPSSignatureScheme(alg SignatureScheme) bool { switch alg { default: return false @@ -140,7 +139,7 @@ func isBoringSignatureScheme(alg SignatureScheme) bool { return true } -func TestBoringServerCipherSuites(t *testing.T) { +func TestFIPSServerCipherSuites(t *testing.T) { serverConfig := testConfig.Clone() serverConfig.Certificates = make([]Certificate, 1) @@ -170,11 +169,11 @@ func TestBoringServerCipherSuites(t *testing.T) { } testClientHello(t, serverConfig, clientHello) - t.Run("fipstls", func(t *testing.T) { - fipstls.Force() - defer fipstls.Abandon() + t.Run("fips140tls", func(t *testing.T) { + fips140tls.Force() + defer fips140tls.TestingOnlyAbandon() msg := "" - if !isBoringCipherSuite(id) { + if !isFIPSCipherSuite(id) { msg = "no cipher suite supported by both client and server" } testClientHelloFailure(t, serverConfig, clientHello, msg) @@ -183,7 +182,7 @@ func TestBoringServerCipherSuites(t *testing.T) { } } -func TestBoringServerCurves(t *testing.T) { +func TestFIPSServerCurves(t *testing.T) { serverConfig := testConfig.Clone() serverConfig.BuildNameToCertificate() @@ -199,14 +198,14 @@ func TestBoringServerCurves(t *testing.T) { t.Fatalf("got error: %v, expected success", err) } - // With fipstls forced, bad curves should be rejected. - t.Run("fipstls", func(t *testing.T) { - fipstls.Force() - defer fipstls.Abandon() + // With fips140tls forced, bad curves should be rejected. + t.Run("fips140tls", func(t *testing.T) { + fips140tls.Force() + defer fips140tls.TestingOnlyAbandon() _, _, err := testHandshake(t, clientConfig, serverConfig) - if err != nil && isBoringCurve(curveid) { + if err != nil && isFIPSCurve(curveid) { t.Fatalf("got error: %v, expected success", err) - } else if err == nil && !isBoringCurve(curveid) { + } else if err == nil && !isFIPSCurve(curveid) { t.Fatalf("got success, expected error") } }) @@ -214,7 +213,7 @@ func TestBoringServerCurves(t *testing.T) { } } -func boringHandshake(t *testing.T, clientConfig, serverConfig *Config) (clientErr, serverErr error) { +func fipsHandshake(t *testing.T, clientConfig, serverConfig *Config) (clientErr, serverErr error) { c, s := localPipe(t) client := Client(c, clientConfig) server := Server(s, serverConfig) @@ -229,7 +228,7 @@ func boringHandshake(t *testing.T, clientConfig, serverConfig *Config) (clientEr return } -func TestBoringServerSignatureAndHash(t *testing.T) { +func TestFIPSServerSignatureAndHash(t *testing.T) { defer func() { testingOnlyForceClientHelloSignatureAlgorithms = nil }() @@ -261,17 +260,17 @@ func TestBoringServerSignatureAndHash(t *testing.T) { // 1.3, and the ECDSA ones bind to the curve used. serverConfig.MaxVersion = VersionTLS12 - clientErr, serverErr := boringHandshake(t, testConfig, serverConfig) + clientErr, serverErr := fipsHandshake(t, testConfig, serverConfig) if clientErr != nil { t.Fatalf("expected handshake with %#x to succeed; client error: %v; server error: %v", sigHash, clientErr, serverErr) } - // With fipstls forced, bad curves should be rejected. - t.Run("fipstls", func(t *testing.T) { - fipstls.Force() - defer fipstls.Abandon() - clientErr, _ := boringHandshake(t, testConfig, serverConfig) - if isBoringSignatureScheme(sigHash) { + // With fips140tls forced, bad curves should be rejected. + t.Run("fips140tls", func(t *testing.T) { + fips140tls.Force() + defer fips140tls.TestingOnlyAbandon() + clientErr, _ := fipsHandshake(t, testConfig, serverConfig) + if isFIPSSignatureScheme(sigHash) { if clientErr != nil { t.Fatalf("expected handshake with %#x to succeed; err=%v", sigHash, clientErr) } @@ -285,11 +284,11 @@ func TestBoringServerSignatureAndHash(t *testing.T) { } } -func TestBoringClientHello(t *testing.T) { +func TestFIPSClientHello(t *testing.T) { // Test that no matter what we put in the client config, // the client does not offer non-FIPS configurations. - fipstls.Force() - defer fipstls.Abandon() + fips140tls.Force() + defer fips140tls.TestingOnlyAbandon() c, s := net.Pipe() defer c.Close() @@ -313,52 +312,57 @@ func TestBoringClientHello(t *testing.T) { t.Fatalf("unexpected message type %T", msg) } - if !isBoringVersion(hello.vers) { + if !isFIPSVersion(hello.vers) { t.Errorf("client vers=%#x", hello.vers) } for _, v := range hello.supportedVersions { - if !isBoringVersion(v) { + if !isFIPSVersion(v) { t.Errorf("client offered disallowed version %#x", v) } } for _, id := range hello.cipherSuites { - if !isBoringCipherSuite(id) { + if !isFIPSCipherSuite(id) { t.Errorf("client offered disallowed suite %#x", id) } } for _, id := range hello.supportedCurves { - if !isBoringCurve(id) { + if !isFIPSCurve(id) { t.Errorf("client offered disallowed curve %d", id) } } for _, sigHash := range hello.supportedSignatureAlgorithms { - if !isBoringSignatureScheme(sigHash) { + if !isFIPSSignatureScheme(sigHash) { t.Errorf("client offered disallowed signature-and-hash %v", sigHash) } } } -func TestBoringCertAlgs(t *testing.T) { - // NaCl, arm and wasm time out generating keys. Nothing in this test is architecture-specific, so just don't bother on those. - if runtime.GOOS == "nacl" || runtime.GOARCH == "arm" || runtime.GOOS == "js" { +func TestFIPSCertAlgs(t *testing.T) { + // arm and wasm time out generating keys. Nothing in this test is + // architecture-specific, so just don't bother on those. + if testenv.CPUIsSlow() { t.Skipf("skipping on %s/%s because key generation takes too long", runtime.GOOS, runtime.GOARCH) } // Set up some roots, intermediate CAs, and leaf certs with various algorithms. // X_Y is X signed by Y. - R1 := boringCert(t, "R1", boringRSAKey(t, 2048), nil, boringCertCA|boringCertFIPSOK) - R2 := boringCert(t, "R2", boringRSAKey(t, 512), nil, boringCertCA) + R1 := fipsCert(t, "R1", fipsRSAKey(t, 2048), nil, fipsCertCA|fipsCertFIPSOK) + R2 := fipsCert(t, "R2", fipsRSAKey(t, 512), nil, fipsCertCA) + R3 := fipsCert(t, "R3", fipsRSAKey(t, 4096), nil, fipsCertCA|fipsCertFIPSOK) - M1_R1 := boringCert(t, "M1_R1", boringECDSAKey(t, elliptic.P256()), R1, boringCertCA|boringCertFIPSOK) - M2_R1 := boringCert(t, "M2_R1", boringECDSAKey(t, elliptic.P224()), R1, boringCertCA) + M1_R1 := fipsCert(t, "M1_R1", fipsECDSAKey(t, elliptic.P256()), R1, fipsCertCA|fipsCertFIPSOK) + M2_R1 := fipsCert(t, "M2_R1", fipsECDSAKey(t, elliptic.P224()), R1, fipsCertCA) - I_R1 := boringCert(t, "I_R1", boringRSAKey(t, 3072), R1, boringCertCA|boringCertFIPSOK) - I_R2 := boringCert(t, "I_R2", I_R1.key, R2, boringCertCA|boringCertFIPSOK) - I_M1 := boringCert(t, "I_M1", I_R1.key, M1_R1, boringCertCA|boringCertFIPSOK) - I_M2 := boringCert(t, "I_M2", I_R1.key, M2_R1, boringCertCA|boringCertFIPSOK) + I_R1 := fipsCert(t, "I_R1", fipsRSAKey(t, 3072), R1, fipsCertCA|fipsCertFIPSOK) + I_R2 := fipsCert(t, "I_R2", I_R1.key, R2, fipsCertCA|fipsCertFIPSOK) + I_M1 := fipsCert(t, "I_M1", I_R1.key, M1_R1, fipsCertCA|fipsCertFIPSOK) + I_M2 := fipsCert(t, "I_M2", I_R1.key, M2_R1, fipsCertCA|fipsCertFIPSOK) - L1_I := boringCert(t, "L1_I", boringECDSAKey(t, elliptic.P384()), I_R1, boringCertLeaf|boringCertFIPSOK) - L2_I := boringCert(t, "L2_I", boringRSAKey(t, 1024), I_R1, boringCertLeaf) + I_R3 := fipsCert(t, "I_R3", fipsRSAKey(t, 3072), R3, fipsCertCA|fipsCertFIPSOK) + fipsCert(t, "I_R3", I_R3.key, R3, fipsCertCA|fipsCertFIPSOK) + + L1_I := fipsCert(t, "L1_I", fipsECDSAKey(t, elliptic.P384()), I_R1, fipsCertLeaf|fipsCertFIPSOK) + L2_I := fipsCert(t, "L2_I", fipsRSAKey(t, 1024), I_R1, fipsCertLeaf) // client verifying server cert testServerCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) { @@ -371,7 +375,7 @@ func TestBoringCertAlgs(t *testing.T) { serverConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}} serverConfig.BuildNameToCertificate() - clientErr, _ := boringHandshake(t, clientConfig, serverConfig) + clientErr, _ := fipsHandshake(t, clientConfig, serverConfig) if (clientErr == nil) == ok { if ok { @@ -398,7 +402,7 @@ func TestBoringCertAlgs(t *testing.T) { serverConfig.ClientCAs = pool serverConfig.ClientAuth = RequireAndVerifyClientCert - _, serverErr := boringHandshake(t, clientConfig, serverConfig) + _, serverErr := fipsHandshake(t, clientConfig, serverConfig) if (serverErr == nil) == ok { if ok { @@ -421,10 +425,10 @@ func TestBoringCertAlgs(t *testing.T) { r1pool.AddCert(R1.cert) testServerCert(t, "basic", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true) testClientCert(t, "basic (client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true) - fipstls.Force() + fips140tls.Force() testServerCert(t, "basic (fips)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false) testClientCert(t, "basic (fips, client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false) - fipstls.Abandon() + fips140tls.TestingOnlyAbandon() if t.Failed() { t.Fatal("basic test failed, skipping exhaustive test") @@ -445,7 +449,7 @@ func TestBoringCertAlgs(t *testing.T) { reachableFIPS := map[string]bool{leaf.parentOrg: leaf.fipsOK} list := [][]byte{leaf.der} listName := leaf.name - addList := func(cond int, c *boringCertificate) { + addList := func(cond int, c *fipsCertificate) { if cond != 0 { list = append(list, c.der) listName += "," + c.name @@ -469,7 +473,7 @@ func TestBoringCertAlgs(t *testing.T) { rootName := "," shouldVerify := false shouldVerifyFIPS := false - addRoot := func(cond int, c *boringCertificate) { + addRoot := func(cond int, c *fipsCertificate) { if cond != 0 { rootName += "," + c.name pool.AddCert(c.cert) @@ -486,22 +490,22 @@ func TestBoringCertAlgs(t *testing.T) { rootName = rootName[1:] // strip leading comma testServerCert(t, listName+"->"+rootName[1:], pool, leaf.key, list, shouldVerify) testClientCert(t, listName+"->"+rootName[1:]+"(client cert)", pool, leaf.key, list, shouldVerify) - fipstls.Force() + fips140tls.Force() testServerCert(t, listName+"->"+rootName[1:]+" (fips)", pool, leaf.key, list, shouldVerifyFIPS) testClientCert(t, listName+"->"+rootName[1:]+" (fips, client cert)", pool, leaf.key, list, shouldVerifyFIPS) - fipstls.Abandon() + fips140tls.TestingOnlyAbandon() } } } } const ( - boringCertCA = iota - boringCertLeaf - boringCertFIPSOK = 0x80 + fipsCertCA = iota + fipsCertLeaf + fipsCertFIPSOK = 0x80 ) -func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey { +func fipsRSAKey(t *testing.T, size int) *rsa.PrivateKey { k, err := rsa.GenerateKey(rand.Reader, size) if err != nil { t.Fatal(err) @@ -509,7 +513,7 @@ func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey { return k } -func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey { +func fipsECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey { k, err := ecdsa.GenerateKey(curve, rand.Reader) if err != nil { t.Fatal(err) @@ -517,7 +521,7 @@ func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey { return k } -type boringCertificate struct { +type fipsCertificate struct { name string org string parentOrg string @@ -527,7 +531,7 @@ type boringCertificate struct { fipsOK bool } -func boringCert(t *testing.T, name string, key interface{}, parent *boringCertificate, mode int) *boringCertificate { +func fipsCert(t *testing.T, name string, key interface{}, parent *fipsCertificate, mode int) *fipsCertificate { org := name parentOrg := "" if i := strings.Index(org, "_"); i >= 0 { @@ -546,7 +550,7 @@ func boringCert(t *testing.T, name string, key interface{}, parent *boringCertif ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, BasicConstraintsValid: true, } - if mode&^boringCertFIPSOK == boringCertLeaf { + if mode&^fipsCertFIPSOK == fipsCertLeaf { tmpl.DNSNames = []string{"example.com"} } else { tmpl.IsCA = true @@ -564,11 +568,14 @@ func boringCert(t *testing.T, name string, key interface{}, parent *boringCertif } var pub interface{} + var desc string switch k := key.(type) { case *rsa.PrivateKey: pub = &k.PublicKey + desc = fmt.Sprintf("RSA-%d", k.N.BitLen()) case *ecdsa.PrivateKey: pub = &k.PublicKey + desc = "ECDSA-" + k.Curve.Params().Name default: t.Fatalf("invalid key %T", key) } @@ -582,8 +589,15 @@ func boringCert(t *testing.T, name string, key interface{}, parent *boringCertif t.Fatal(err) } - fipsOK := mode&boringCertFIPSOK != 0 - return &boringCertificate{name, org, parentOrg, der, cert, key, fipsOK} + fips140tls.Force() + defer fips140tls.TestingOnlyAbandon() + + fipsOK := mode&fipsCertFIPSOK != 0 + if fipsAllowCert(cert) != fipsOK { + t.Errorf("fipsAllowCert(cert with %s key) = %v, want %v", desc, !fipsOK, fipsOK) + } + + return &fipsCertificate{name, org, parentOrg, der, cert, key, fipsOK} } // A self-signed test certificate with an RSA key of size 2048, for testing diff --git a/fipsonly/fipsonly.go b/fipsonly/fipsonly.go index e5e4783..e702f44 100644 --- a/fipsonly/fipsonly.go +++ b/fipsonly/fipsonly.go @@ -19,11 +19,11 @@ package fipsonly // new source file and not modifying any existing source files. import ( - "crypto/internal/boring/fipstls" "crypto/internal/boring/sig" + "crypto/tls/internal/fips140tls" ) func init() { - fipstls.Force() + fips140tls.Force() sig.FIPSOnly() } diff --git a/fipsonly/fipsonly_test.go b/fipsonly/fipsonly_test.go index f8485dc..027bc22 100644 --- a/fipsonly/fipsonly_test.go +++ b/fipsonly/fipsonly_test.go @@ -7,12 +7,12 @@ package fipsonly import ( - "crypto/internal/boring/fipstls" + "crypto/tls/internal/fips140tls" "testing" ) func Test(t *testing.T) { - if !fipstls.Required() { - t.Fatal("fipstls.Required() = false, must be true") + if !fips140tls.Required() { + t.Fatal("fips140tls.Required() = false, must be true") } } diff --git a/handshake_client.go b/handshake_client.go index be88278..2ee1136 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -15,6 +15,7 @@ import ( "crypto/internal/hpke" "crypto/rsa" "crypto/subtle" + "crypto/tls/internal/fips140tls" "crypto/x509" "errors" "fmt" @@ -142,7 +143,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon if len(hello.supportedVersions) == 1 { hello.cipherSuites = nil } - if needFIPS() { + if fips140tls.Required() { hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13FIPS...) } else if hasAESGCMHardwareSupport { hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...) @@ -632,11 +633,11 @@ func (hs *clientHandshakeState) pickCipherSuite() error { return errors.New("tls: server chose an unconfigured cipher suite") } - if hs.c.config.CipherSuites == nil && !needFIPS() && rsaKexCiphers[hs.suite.id] { + if hs.c.config.CipherSuites == nil && !fips140tls.Required() && rsaKexCiphers[hs.suite.id] { tlsrsakex.Value() // ensure godebug is initialized tlsrsakex.IncNonDefault() } - if hs.c.config.CipherSuites == nil && !needFIPS() && tdesCiphers[hs.suite.id] { + if hs.c.config.CipherSuites == nil && !fips140tls.Required() && tdesCiphers[hs.suite.id] { tls3des.Value() // ensure godebug is initialized tls3des.IncNonDefault() } @@ -1112,8 +1113,13 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error { for _, cert := range certs[1:] { opts.Intermediates.AddCert(cert) } - var err error - c.verifiedChains, err = certs[0].Verify(opts) + chains, err := certs[0].Verify(opts) + if err != nil { + c.sendAlert(alertBadCertificate) + return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} + } + + c.verifiedChains, err = fipsAllowedChains(chains) if err != nil { c.sendAlert(alertBadCertificate) return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} @@ -1130,8 +1136,13 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error { for _, cert := range certs[1:] { opts.Intermediates.AddCert(cert) } - var err error - c.verifiedChains, err = certs[0].Verify(opts) + chains, err := certs[0].Verify(opts) + if err != nil { + c.sendAlert(alertBadCertificate) + return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} + } + + c.verifiedChains, err = fipsAllowedChains(chains) if err != nil { c.sendAlert(alertBadCertificate) return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} diff --git a/handshake_server.go b/handshake_server.go index 740c149..6fb1755 100644 --- a/handshake_server.go +++ b/handshake_server.go @@ -11,6 +11,7 @@ import ( "crypto/ed25519" "crypto/rsa" "crypto/subtle" + "crypto/tls/internal/fips140tls" "crypto/x509" "errors" "fmt" @@ -372,11 +373,11 @@ func (hs *serverHandshakeState) pickCipherSuite() error { } c.cipherSuite = hs.suite.id - if c.config.CipherSuites == nil && !needFIPS() && rsaKexCiphers[hs.suite.id] { + if c.config.CipherSuites == nil && !fips140tls.Required() && rsaKexCiphers[hs.suite.id] { tlsrsakex.Value() // ensure godebug is initialized tlsrsakex.IncNonDefault() } - if c.config.CipherSuites == nil && !needFIPS() && tdesCiphers[hs.suite.id] { + if c.config.CipherSuites == nil && !fips140tls.Required() && tdesCiphers[hs.suite.id] { tls3des.Value() // ensure godebug is initialized tls3des.IncNonDefault() } @@ -923,7 +924,11 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error { return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} } - c.verifiedChains = chains + c.verifiedChains, err = fipsAllowedChains(chains) + if err != nil { + c.sendAlert(alertBadCertificate) + return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} + } } c.peerCertificates = certs diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index c2349ad..64c6b13 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -12,6 +12,7 @@ import ( "crypto/internal/fips140/mlkem" "crypto/internal/fips140/tls13" "crypto/rsa" + "crypto/tls/internal/fips140tls" "errors" "hash" "internal/byteorder" @@ -162,7 +163,7 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) { preferenceList = defaultCipherSuitesTLS13NoAES } - if needFIPS() { + if fips140tls.Required() { preferenceList = defaultCipherSuitesTLS13FIPS } for _, suiteID := range preferenceList { diff --git a/internal/fips140tls/fipstls.go b/internal/fips140tls/fipstls.go new file mode 100644 index 0000000..24d78d6 --- /dev/null +++ b/internal/fips140tls/fipstls.go @@ -0,0 +1,37 @@ +// 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 fips140tls controls whether crypto/tls requires FIPS-approved settings. +package fips140tls + +import ( + "crypto/internal/fips140" + "sync/atomic" +) + +var required atomic.Bool + +func init() { + if fips140.Enabled { + Force() + } +} + +// Force forces crypto/tls to restrict TLS configurations to FIPS-approved settings. +// By design, this call is impossible to undo (except in tests). +func Force() { + required.Store(true) +} + +// Required reports whether FIPS-approved settings are required. +// +// Required is true if FIPS 140-3 mode is enabled with GODEBUG=fips140=on, or if +// the crypto/tls/fipsonly package is imported by a Go+BoringCrypto build. +func Required() bool { + return required.Load() +} + +func TestingOnlyAbandon() { + required.Store(false) +} diff --git a/notboring.go b/notboring.go deleted file mode 100644 index bdbc32e..0000000 --- a/notboring.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2022 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. - -//go:build !boringcrypto - -package tls - -func needFIPS() bool { return false } From 83cefcdeedd3adc553b8e864a772a64be014b10b Mon Sep 17 00:00:00 2001 From: cuishuang Date: Wed, 20 Nov 2024 21:56:27 +0800 Subject: [PATCH 23/34] all: fix some function names and typos in comment Change-Id: I07e7c8eaa5bd4bac0d576b2f2f4cd3f81b0b77a4 Reviewed-on: https://go-review.googlesource.com/c/go/+/630055 LUCI-TryBot-Result: Go LUCI Commit-Queue: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Reviewed-by: Russ Cox Auto-Submit: Ian Lance Taylor --- common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.go b/common.go index 662f1fc..1f73e50 100644 --- a/common.go +++ b/common.go @@ -801,7 +801,7 @@ type Config struct { // be VersionTLS13. // // When EncryptedClientHelloConfigList is set, the handshake will only - // succeed if ECH is sucessfully negotiated. If the server rejects ECH, + // succeed if ECH is successfully negotiated. If the server rejects ECH, // an ECHRejectionError error will be returned, which may contain a new // ECHConfigList that the server suggests using. // From 212bbb2c77fa2adf48e643b7ae815cd1cdc746e9 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Tue, 29 Oct 2024 20:22:27 -0700 Subject: [PATCH 24/34] crypto/tls: add server-side ECH Adds support for server-side ECH. We make a couple of implementation decisions that are not completely in-line with the spec. In particular, we don't enforce that the SNI matches the ECHConfig public_name, and we implement a hybrid shared/backend mode (rather than shared or split mode, as described in Section 7). Both of these match the behavior of BoringSSL. The hybrid server mode will either act as a shared mode server, where-in the server accepts "outer" client hellos and unwraps them before processing the "inner" hello, or accepts bare "inner" hellos initially. This lets the server operate either transparently as a shared mode server, or a backend server, in Section 7 terminology. This seems like the best implementation choice for a TLS library. Fixes #68500 Change-Id: Ife69db7c1886610742e95e76b0ca92587e6d7ed4 Reviewed-on: https://go-review.googlesource.com/c/go/+/623576 Reviewed-by: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Daniel McCarney Auto-Submit: Roland Shoemaker Reviewed-by: Dmitri Shuralyov --- bogo_config.json | 16 +- bogo_shim_test.go | 41 +++- common.go | 47 +++- ech.go | 472 ++++++++++++++++++++++++++++++++----- handshake_client.go | 8 +- handshake_client_tls13.go | 8 +- handshake_messages.go | 6 +- handshake_messages_test.go | 3 + handshake_server.go | 37 ++- handshake_server_test.go | 5 +- handshake_server_tls13.go | 98 ++++++++ tls_test.go | 124 +++++++++- 12 files changed, 770 insertions(+), 95 deletions(-) diff --git a/bogo_config.json b/bogo_config.json index 2363dd5..cfd9579 100644 --- a/bogo_config.json +++ b/bogo_config.json @@ -12,7 +12,7 @@ "TLS-ECH-Client-Reject-ResumeInnerSession-TLS12": "We won't attempt to negotiate 1.2 if ECH is enabled (we could possibly test this if we had the ability to indicate not to send ECH on resumption?)", - "TLS-ECH-Client-Reject-EarlyDataRejected": "We don't support switiching out ECH configs with this level of granularity", + "TLS-ECH-Client-Reject-EarlyDataRejected": "Go does not support early (0-RTT) data", "TLS-ECH-Client-NoNPN": "We don't support NPN", @@ -30,8 +30,12 @@ "TLS-ECH-Client-NoSupportedConfigs": "We don't support fallback to cleartext when there are no valid ECH configs", "TLS-ECH-Client-SkipInvalidPublicName": "We don't support fallback to cleartext when there are no valid ECH configs", + "TLS-ECH-Server-EarlyData": "Go does not support early (0-RTT) data", + "TLS-ECH-Server-EarlyDataRejected": "Go does not support early (0-RTT) data", + + "CurveTest-Client-Kyber-TLS13": "Temporarily disabled since the curve ID is not exposed and it cannot be correctly configured", + "CurveTest-Server-Kyber-TLS13": "Temporarily disabled since the curve ID is not exposed and it cannot be correctly configured", - "*ECH-Server*": "no ECH server support", "SendV2ClientHello*": "We don't support SSLv2", "*QUIC*": "No QUIC support", "Compliance-fips*": "No FIPS", @@ -229,5 +233,11 @@ "EarlyData-UnexpectedHandshake-Server-TLS13": "TODO: first pass, this should be fixed", "EarlyData-CipherMismatch-Client-TLS13": "TODO: first pass, this should be fixed", "Resume-Server-UnofferedCipher-TLS13": "TODO: first pass, this should be fixed" - } + }, + "AllCurves": [ + 23, + 24, + 25, + 29 + ] } diff --git a/bogo_shim_test.go b/bogo_shim_test.go index bb78c64..b294608 100644 --- a/bogo_shim_test.go +++ b/bogo_shim_test.go @@ -76,6 +76,9 @@ var ( onResumeExpectECHAccepted = flag.Bool("on-resume-expect-ech-accept", false, "") _ = flag.Bool("on-resume-expect-no-ech-name-override", false, "") expectedServerName = flag.String("expect-server-name", "", "") + echServerConfig = flagStringSlice("ech-server-config", "") + echServerKey = flagStringSlice("ech-server-key", "") + echServerRetryConfig = flagStringSlice("ech-is-retry-config", "") expectSessionMiss = flag.Bool("expect-session-miss", false, "") @@ -105,12 +108,12 @@ func flagStringSlice(name, usage string) *stringSlice { return f } -func (saf stringSlice) String() string { - return strings.Join(saf, ",") +func (saf *stringSlice) String() string { + return strings.Join(*saf, ",") } -func (saf stringSlice) Set(s string) error { - saf = append(saf, s) +func (saf *stringSlice) Set(s string) error { + *saf = append(*saf, s) return nil } @@ -248,6 +251,29 @@ func bogoShim() { } } + if len(*echServerConfig) != 0 { + if len(*echServerConfig) != len(*echServerKey) || len(*echServerConfig) != len(*echServerRetryConfig) { + log.Fatal("-ech-server-config, -ech-server-key, and -ech-is-retry-config mismatch") + } + + for i, c := range *echServerConfig { + configBytes, err := base64.StdEncoding.DecodeString(c) + if err != nil { + log.Fatalf("parse ech-server-config err: %s", err) + } + privBytes, err := base64.StdEncoding.DecodeString((*echServerKey)[i]) + if err != nil { + log.Fatalf("parse ech-server-key err: %s", err) + } + + cfg.EncryptedClientHelloKeys = append(cfg.EncryptedClientHelloKeys, EncryptedClientHelloKey{ + Config: configBytes, + PrivateKey: privBytes, + SendAsRetry: (*echServerRetryConfig)[i] == "1", + }) + } + } + for i := 0; i < *resumeCount+1; i++ { if i > 0 && (*onResumeECHConfigListB64 != "") { echConfigList, err := base64.StdEncoding.DecodeString(*onResumeECHConfigListB64) @@ -446,8 +472,11 @@ func TestBogoSuite(t *testing.T) { // are present in the output. They are only checked if -bogo-filter // was not passed. assertResults := map[string]string{ - "CurveTest-Client-Kyber-TLS13": "PASS", - "CurveTest-Server-Kyber-TLS13": "PASS", + // TODO: these tests are temporarily disabled, since we don't expose the + // necessary curve ID, and it's currently not possible to correctly + // configure it. + // "CurveTest-Client-Kyber-TLS13": "PASS", + // "CurveTest-Server-Kyber-TLS13": "PASS", } for name, result := range results.Tests { diff --git a/common.go b/common.go index 1f73e50..56f2acf 100644 --- a/common.go +++ b/common.go @@ -791,8 +791,10 @@ type Config struct { // EncryptedClientHelloConfigList is a serialized ECHConfigList. If // provided, clients will attempt to connect to servers using Encrypted - // Client Hello (ECH) using one of the provided ECHConfigs. Servers - // currently ignore this field. + // Client Hello (ECH) using one of the provided ECHConfigs. + // + // Servers do not use this field. In order to configure ECH for servers, see + // the EncryptedClientHelloKeys field. // // If the list contains no valid ECH configs, the handshake will fail // and return an error. @@ -810,9 +812,11 @@ type Config struct { EncryptedClientHelloConfigList []byte // EncryptedClientHelloRejectionVerify, if not nil, is called when ECH is - // rejected, in order to verify the ECH provider certificate in the outer - // Client Hello. If it returns a non-nil error, the handshake is aborted and - // that error results. + // rejected by the remote server, in order to verify the ECH provider + // certificate in the outer Client Hello. If it returns a non-nil error, the + // handshake is aborted and that error results. + // + // On the server side this field is not used. // // Unlike VerifyPeerCertificate and VerifyConnection, normal certificate // verification will not be performed before calling @@ -824,6 +828,20 @@ type Config struct { // when ECH is rejected, even if set, and InsecureSkipVerify is ignored. EncryptedClientHelloRejectionVerify func(ConnectionState) error + // EncryptedClientHelloKeys are the ECH keys to use when a client + // attempts ECH. + // + // If EncryptedClientHelloKeys is set, MinVersion, if set, must be + // VersionTLS13. + // + // If a client attempts ECH, but it is rejected by the server, the server + // will send a list of configs to retry based on the set of + // EncryptedClientHelloKeys which have the SendAsRetry field set. + // + // On the client side, this field is ignored. In order to configure ECH for + // clients, see the EncryptedClientHelloConfigList field. + EncryptedClientHelloKeys []EncryptedClientHelloKey + // mutex protects sessionTicketKeys and autoSessionTicketKeys. mutex sync.RWMutex // sessionTicketKeys contains zero or more ticket keys. If set, it means @@ -837,6 +855,24 @@ type Config struct { autoSessionTicketKeys []ticketKey } +// EncryptedClientHelloKey holds a private key that is associated +// with a specific ECH config known to a client. +type EncryptedClientHelloKey struct { + // Config should be a marshalled ECHConfig associated with PrivateKey. This + // must match the config provided to clients byte-for-byte. The config + // should only specify the DHKEM(X25519, HKDF-SHA256) KEM ID (0x0020), the + // HKDF-SHA256 KDF ID (0x0001), and a subset of the following AEAD IDs: + // AES-128-GCM (0x0000), AES-256-GCM (0x0001), ChaCha20Poly1305 (0x0002). + Config []byte + // PrivateKey should be a marshalled private key. Currently, we expect + // this to be the output of [ecdh.PrivateKey.Bytes]. + PrivateKey []byte + // SendAsRetry indicates if Config should be sent as part of the list of + // retry configs when ECH is requested by the client but rejected by the + // server. + SendAsRetry bool +} + const ( // ticketKeyLifetime is how long a ticket key remains valid and can be used to // resume a client connection. @@ -913,6 +949,7 @@ func (c *Config) Clone() *Config { KeyLogWriter: c.KeyLogWriter, EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList, EncryptedClientHelloRejectionVerify: c.EncryptedClientHelloRejectionVerify, + EncryptedClientHelloKeys: c.EncryptedClientHelloKeys, sessionTicketKeys: c.sessionTicketKeys, autoSessionTicketKeys: c.autoSessionTicketKeys, } diff --git a/ech.go b/ech.go index 7bf6858..55d5217 100644 --- a/ech.go +++ b/ech.go @@ -5,13 +5,28 @@ package tls import ( + "bytes" "crypto/internal/hpke" "errors" + "fmt" + "slices" "strings" "golang.org/x/crypto/cryptobyte" ) +// sortedSupportedAEADs is just a sorted version of hpke.SupportedAEADS. +// We need this so that when we insert them into ECHConfigs the ordering +// is stable. +var sortedSupportedAEADs []uint16 + +func init() { + for aeadID := range hpke.SupportedAEADs { + sortedSupportedAEADs = append(sortedSupportedAEADs, aeadID) + } + slices.Sort(sortedSupportedAEADs) +} + type echCipher struct { KDFID uint16 AEADID uint16 @@ -40,12 +55,77 @@ type echConfig struct { var errMalformedECHConfig = errors.New("tls: malformed ECHConfigList") +func parseECHConfig(enc []byte) (skip bool, ec echConfig, err error) { + s := cryptobyte.String(enc) + ec.raw = []byte(enc) + if !s.ReadUint16(&ec.Version) { + return false, echConfig{}, errMalformedECHConfig + } + if !s.ReadUint16(&ec.Length) { + return false, echConfig{}, errMalformedECHConfig + } + if len(ec.raw) < int(ec.Length)+4 { + return false, echConfig{}, errMalformedECHConfig + } + ec.raw = ec.raw[:ec.Length+4] + if ec.Version != extensionEncryptedClientHello { + s.Skip(int(ec.Length)) + return true, echConfig{}, nil + } + if !s.ReadUint8(&ec.ConfigID) { + return false, echConfig{}, errMalformedECHConfig + } + if !s.ReadUint16(&ec.KemID) { + return false, echConfig{}, errMalformedECHConfig + } + if !readUint16LengthPrefixed(&s, &ec.PublicKey) { + return false, echConfig{}, errMalformedECHConfig + } + var cipherSuites cryptobyte.String + if !s.ReadUint16LengthPrefixed(&cipherSuites) { + return false, echConfig{}, errMalformedECHConfig + } + for !cipherSuites.Empty() { + var c echCipher + if !cipherSuites.ReadUint16(&c.KDFID) { + return false, echConfig{}, errMalformedECHConfig + } + if !cipherSuites.ReadUint16(&c.AEADID) { + return false, echConfig{}, errMalformedECHConfig + } + ec.SymmetricCipherSuite = append(ec.SymmetricCipherSuite, c) + } + if !s.ReadUint8(&ec.MaxNameLength) { + return false, echConfig{}, errMalformedECHConfig + } + var publicName cryptobyte.String + if !s.ReadUint8LengthPrefixed(&publicName) { + return false, echConfig{}, errMalformedECHConfig + } + ec.PublicName = publicName + var extensions cryptobyte.String + if !s.ReadUint16LengthPrefixed(&extensions) { + return false, echConfig{}, errMalformedECHConfig + } + for !extensions.Empty() { + var e echExtension + if !extensions.ReadUint16(&e.Type) { + return false, echConfig{}, errMalformedECHConfig + } + if !extensions.ReadUint16LengthPrefixed((*cryptobyte.String)(&e.Data)) { + return false, echConfig{}, errMalformedECHConfig + } + ec.Extensions = append(ec.Extensions, e) + } + + return false, ec, nil +} + // parseECHConfigList parses a draft-ietf-tls-esni-18 ECHConfigList, returning a // slice of parsed ECHConfigs, in the same order they were parsed, or an error // if the list is malformed. func parseECHConfigList(data []byte) ([]echConfig, error) { s := cryptobyte.String(data) - // Skip the length prefix var length uint16 if !s.ReadUint16(&length) { return nil, errMalformedECHConfig @@ -55,69 +135,18 @@ func parseECHConfigList(data []byte) ([]echConfig, error) { } var configs []echConfig for len(s) > 0 { - var ec echConfig - ec.raw = []byte(s) - if !s.ReadUint16(&ec.Version) { - return nil, errMalformedECHConfig + if len(s) < 4 { + return nil, errors.New("tls: malformed ECHConfig") } - if !s.ReadUint16(&ec.Length) { - return nil, errMalformedECHConfig + configLen := uint16(s[2])<<8 | uint16(s[3]) + skip, ec, err := parseECHConfig(s) + if err != nil { + return nil, err } - if len(ec.raw) < int(ec.Length)+4 { - return nil, errMalformedECHConfig + s = s[configLen+4:] + if !skip { + configs = append(configs, ec) } - ec.raw = ec.raw[:ec.Length+4] - if ec.Version != extensionEncryptedClientHello { - s.Skip(int(ec.Length)) - continue - } - if !s.ReadUint8(&ec.ConfigID) { - return nil, errMalformedECHConfig - } - if !s.ReadUint16(&ec.KemID) { - return nil, errMalformedECHConfig - } - if !s.ReadUint16LengthPrefixed((*cryptobyte.String)(&ec.PublicKey)) { - return nil, errMalformedECHConfig - } - var cipherSuites cryptobyte.String - if !s.ReadUint16LengthPrefixed(&cipherSuites) { - return nil, errMalformedECHConfig - } - for !cipherSuites.Empty() { - var c echCipher - if !cipherSuites.ReadUint16(&c.KDFID) { - return nil, errMalformedECHConfig - } - if !cipherSuites.ReadUint16(&c.AEADID) { - return nil, errMalformedECHConfig - } - ec.SymmetricCipherSuite = append(ec.SymmetricCipherSuite, c) - } - if !s.ReadUint8(&ec.MaxNameLength) { - return nil, errMalformedECHConfig - } - var publicName cryptobyte.String - if !s.ReadUint8LengthPrefixed(&publicName) { - return nil, errMalformedECHConfig - } - ec.PublicName = publicName - var extensions cryptobyte.String - if !s.ReadUint16LengthPrefixed(&extensions) { - return nil, errMalformedECHConfig - } - for !extensions.Empty() { - var e echExtension - if !extensions.ReadUint16(&e.Type) { - return nil, errMalformedECHConfig - } - if !extensions.ReadUint16LengthPrefixed((*cryptobyte.String)(&e.Data)) { - return nil, errMalformedECHConfig - } - ec.Extensions = append(ec.Extensions, e) - } - - configs = append(configs, ec) } return configs, nil } @@ -195,6 +224,175 @@ func encodeInnerClientHello(inner *clientHelloMsg, maxNameLength int) ([]byte, e return append(h, make([]byte, paddingLen)...), nil } +func skipUint8LengthPrefixed(s *cryptobyte.String) bool { + var skip uint8 + if !s.ReadUint8(&skip) { + return false + } + return s.Skip(int(skip)) +} + +func skipUint16LengthPrefixed(s *cryptobyte.String) bool { + var skip uint16 + if !s.ReadUint16(&skip) { + return false + } + return s.Skip(int(skip)) +} + +type rawExtension struct { + extType uint16 + data []byte +} + +func extractRawExtensions(hello *clientHelloMsg) ([]rawExtension, error) { + s := cryptobyte.String(hello.original) + if !s.Skip(4+2+32) || // header, version, random + !skipUint8LengthPrefixed(&s) || // session ID + !skipUint16LengthPrefixed(&s) || // cipher suites + !skipUint8LengthPrefixed(&s) { // compression methods + return nil, errors.New("tls: malformed outer client hello") + } + var rawExtensions []rawExtension + var extensions cryptobyte.String + if !s.ReadUint16LengthPrefixed(&extensions) { + return nil, errors.New("tls: malformed outer client hello") + } + + for !extensions.Empty() { + var extension uint16 + var extData cryptobyte.String + if !extensions.ReadUint16(&extension) || + !extensions.ReadUint16LengthPrefixed(&extData) { + return nil, errors.New("tls: invalid inner client hello") + } + rawExtensions = append(rawExtensions, rawExtension{extension, extData}) + } + return rawExtensions, nil +} + +func decodeInnerClientHello(outer *clientHelloMsg, encoded []byte) (*clientHelloMsg, error) { + // Reconstructing the inner client hello from its encoded form is somewhat + // complicated. It is missing its header (message type and length), session + // ID, and the extensions may be compressed. Since we need to put the + // extensions back in the same order as they were in the raw outer hello, + // and since we don't store the raw extensions, or the order we parsed them + // in, we need to reparse the raw extensions from the outer hello in order + // to properly insert them into the inner hello. This _should_ result in raw + // bytes which match the hello as it was generated by the client. + innerReader := cryptobyte.String(encoded) + var versionAndRandom, sessionID, cipherSuites, compressionMethods []byte + var extensions cryptobyte.String + if !innerReader.ReadBytes(&versionAndRandom, 2+32) || + !readUint8LengthPrefixed(&innerReader, &sessionID) || + len(sessionID) != 0 || + !readUint16LengthPrefixed(&innerReader, &cipherSuites) || + !readUint8LengthPrefixed(&innerReader, &compressionMethods) || + !innerReader.ReadUint16LengthPrefixed(&extensions) { + return nil, errors.New("tls: invalid inner client hello") + } + + // The specification says we must verify that the trailing padding is all + // zeros. This is kind of weird for TLS messages, where we generally just + // throw away any trailing garbage. + for _, p := range innerReader { + if p != 0 { + return nil, errors.New("tls: invalid inner client hello") + } + } + + rawOuterExts, err := extractRawExtensions(outer) + if err != nil { + return nil, err + } + + recon := cryptobyte.NewBuilder(nil) + recon.AddUint8(typeClientHello) + recon.AddUint24LengthPrefixed(func(recon *cryptobyte.Builder) { + recon.AddBytes(versionAndRandom) + recon.AddUint8LengthPrefixed(func(recon *cryptobyte.Builder) { + recon.AddBytes(outer.sessionId) + }) + recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) { + recon.AddBytes(cipherSuites) + }) + recon.AddUint8LengthPrefixed(func(recon *cryptobyte.Builder) { + recon.AddBytes(compressionMethods) + }) + recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) { + for !extensions.Empty() { + var extension uint16 + var extData cryptobyte.String + if !extensions.ReadUint16(&extension) || + !extensions.ReadUint16LengthPrefixed(&extData) { + recon.SetError(errors.New("tls: invalid inner client hello")) + return + } + if extension == extensionECHOuterExtensions { + if !extData.ReadUint8LengthPrefixed(&extData) { + recon.SetError(errors.New("tls: invalid inner client hello")) + return + } + var i int + for !extData.Empty() { + var extType uint16 + if !extData.ReadUint16(&extType) { + recon.SetError(errors.New("tls: invalid inner client hello")) + return + } + if extType == extensionEncryptedClientHello { + recon.SetError(errors.New("tls: invalid outer extensions")) + return + } + for ; i <= len(rawOuterExts); i++ { + if i == len(rawOuterExts) { + recon.SetError(errors.New("tls: invalid outer extensions")) + return + } + if rawOuterExts[i].extType == extType { + break + } + } + recon.AddUint16(rawOuterExts[i].extType) + recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) { + recon.AddBytes(rawOuterExts[i].data) + }) + } + } else { + recon.AddUint16(extension) + recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) { + recon.AddBytes(extData) + }) + } + } + }) + }) + + reconBytes, err := recon.Bytes() + if err != nil { + return nil, err + } + inner := &clientHelloMsg{} + if !inner.unmarshal(reconBytes) { + return nil, errors.New("tls: invalid reconstructed inner client hello") + } + + if !bytes.Equal(inner.encryptedClientHello, []byte{uint8(innerECHExt)}) { + return nil, errors.New("tls: client sent invalid encrypted_client_hello extension") + } + + if len(inner.supportedVersions) != 1 || (len(inner.supportedVersions) >= 1 && inner.supportedVersions[0] != VersionTLS13) { + return nil, errors.New("tls: client sent encrypted_client_hello extension and offered incompatible versions") + } + + return inner, nil +} + +func decryptECHPayload(context *hpke.Receipient, hello, payload []byte) ([]byte, error) { + outerAAD := bytes.Replace(hello[4:], payload, make([]byte, len(payload)), 1) + return context.Open(outerAAD, payload) +} + func generateOuterECHExt(id uint8, kdfID, aeadID uint16, encodedKey []byte, payload []byte) ([]byte, error) { var b cryptobyte.Builder b.AddUint8(0) // outer @@ -206,7 +404,7 @@ func generateOuterECHExt(id uint8, kdfID, aeadID uint16, encodedKey []byte, payl return b.Bytes() } -func computeAndUpdateOuterECHExtension(outer, inner *clientHelloMsg, ech *echContext, useKey bool) error { +func computeAndUpdateOuterECHExtension(outer, inner *clientHelloMsg, ech *echClientContext, useKey bool) error { var encapKey []byte if useKey { encapKey = ech.encapsulatedKey @@ -281,3 +479,153 @@ type ECHRejectionError struct { func (e *ECHRejectionError) Error() string { return "tls: server rejected ECH" } + +var errMalformedECHExt = errors.New("tls: malformed encrypted_client_hello extension") + +type echExtType uint8 + +const ( + innerECHExt echExtType = 1 + outerECHExt echExtType = 0 +) + +func parseECHExt(ext []byte) (echType echExtType, cs echCipher, configID uint8, encap []byte, payload []byte, err error) { + data := make([]byte, len(ext)) + copy(data, ext) + s := cryptobyte.String(data) + var echInt uint8 + if !s.ReadUint8(&echInt) { + err = errMalformedECHExt + return + } + echType = echExtType(echInt) + if echType == innerECHExt { + if !s.Empty() { + err = errMalformedECHExt + return + } + return echType, cs, 0, nil, nil, nil + } + if echType != outerECHExt { + err = errMalformedECHExt + return + } + if !s.ReadUint16(&cs.KDFID) { + err = errMalformedECHExt + return + } + if !s.ReadUint16(&cs.AEADID) { + err = errMalformedECHExt + return + } + if !s.ReadUint8(&configID) { + err = errMalformedECHExt + return + } + if !readUint16LengthPrefixed(&s, &encap) { + err = errMalformedECHExt + return + } + if !readUint16LengthPrefixed(&s, &payload) { + err = errMalformedECHExt + return + } + + // NOTE: clone encap and payload so that mutating them does not mutate the + // raw extension bytes. + return echType, cs, configID, bytes.Clone(encap), bytes.Clone(payload), nil +} + +func marshalEncryptedClientHelloConfigList(configs []EncryptedClientHelloKey) ([]byte, error) { + builder := cryptobyte.NewBuilder(nil) + builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) { + for _, c := range configs { + builder.AddBytes(c.Config) + } + }) + return builder.Bytes() +} + +func (c *Conn) processECHClientHello(outer *clientHelloMsg) (*clientHelloMsg, *echServerContext, error) { + echType, echCiphersuite, configID, encap, payload, err := parseECHExt(outer.encryptedClientHello) + if err != nil { + c.sendAlert(alertDecodeError) + return nil, nil, errors.New("tls: client sent invalid encrypted_client_hello extension") + } + + if echType == innerECHExt { + return outer, &echServerContext{inner: true}, nil + } + + if len(c.config.EncryptedClientHelloKeys) == 0 { + return outer, nil, nil + } + + for _, echKey := range c.config.EncryptedClientHelloKeys { + skip, config, err := parseECHConfig(echKey.Config) + if err != nil || skip { + c.sendAlert(alertInternalError) + return nil, nil, fmt.Errorf("tls: invalid EncryptedClientHelloKeys Config: %s", err) + } + if skip { + continue + } + echPriv, err := hpke.ParseHPKEPrivateKey(config.KemID, echKey.PrivateKey) + if err != nil { + c.sendAlert(alertInternalError) + return nil, nil, fmt.Errorf("tls: invalid EncryptedClientHelloKeys PrivateKey: %s", err) + } + info := append([]byte("tls ech\x00"), echKey.Config...) + hpkeContext, err := hpke.SetupReceipient(hpke.DHKEM_X25519_HKDF_SHA256, echCiphersuite.KDFID, echCiphersuite.AEADID, echPriv, info, encap) + if err != nil { + // attempt next trial decryption + continue + } + + encodedInner, err := decryptECHPayload(hpkeContext, outer.original, payload) + if err != nil { + // attempt next trial decryption + continue + } + + // NOTE: we do not enforce that the sent server_name matches the ECH + // configs PublicName, since this is not particularly important, and + // the client already had to know what it was in order to properly + // encrypt the payload. This is only a MAY in the spec, so we're not + // doing anything revolutionary. + + echInner, err := decodeInnerClientHello(outer, encodedInner) + if err != nil { + c.sendAlert(alertIllegalParameter) + return nil, nil, errors.New("tls: client sent invalid encrypted_client_hello extension") + } + + c.echAccepted = true + + return echInner, &echServerContext{ + hpkeContext: hpkeContext, + configID: configID, + ciphersuite: echCiphersuite, + }, nil + } + + return outer, nil, nil +} + +func buildRetryConfigList(keys []EncryptedClientHelloKey) ([]byte, error) { + var atLeastOneRetryConfig bool + var retryBuilder cryptobyte.Builder + retryBuilder.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + for _, c := range keys { + if !c.SendAsRetry { + continue + } + atLeastOneRetryConfig = true + b.AddBytes(c.Config) + } + }) + if !atLeastOneRetryConfig { + return nil, nil + } + return retryBuilder.Bytes() +} diff --git a/handshake_client.go b/handshake_client.go index 2ee1136..548b5f0 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -43,7 +43,7 @@ type clientHandshakeState struct { var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme -func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echContext, error) { +func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echClientContext, error) { config := c.config if len(config.ServerName) == 0 && !config.InsecureSkipVerify { return nil, nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") @@ -201,7 +201,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon hello.quicTransportParameters = p } - var ech *echContext + var ech *echClientContext if c.config.EncryptedClientHelloConfigList != nil { if c.config.MinVersion != 0 && c.config.MinVersion < VersionTLS13 { return nil, nil, nil, errors.New("tls: MinVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated") @@ -217,7 +217,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon if echConfig == nil { return nil, nil, nil, errors.New("tls: EncryptedClientHelloConfigList contains no valid configs") } - ech = &echContext{config: echConfig} + ech = &echClientContext{config: echConfig} hello.encryptedClientHello = []byte{1} // indicate inner hello // We need to explicitly set these 1.2 fields to nil, as we do not // marshal them when encoding the inner hello, otherwise transcripts @@ -246,7 +246,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon return hello, keyShareKeys, ech, nil } -type echContext struct { +type echClientContext struct { config *echConfig hpkeContext *hpke.Sender encapsulatedKey []byte diff --git a/handshake_client_tls13.go b/handshake_client_tls13.go index 53f1665..3f4cadb 100644 --- a/handshake_client_tls13.go +++ b/handshake_client_tls13.go @@ -39,7 +39,7 @@ type clientHandshakeStateTLS13 struct { masterSecret *tls13.MasterSecret trafficSecret []byte // client_application_traffic_secret_0 - echContext *echContext + echContext *echClientContext } // handshake requires hs.c, hs.hello, hs.serverHello, hs.keyShareKeys, and, @@ -105,7 +105,7 @@ func (hs *clientHandshakeStateTLS13) handshake() error { if hs.serverHello.encryptedClientHello != nil { c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: unexpected encrypted_client_hello extension in server hello despite ECH being accepted") + return errors.New("tls: unexpected encrypted client hello extension in server hello despite ECH being accepted") } if hs.hello.serverName == "" && hs.serverHello.serverNameAck { @@ -288,7 +288,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { } else if hs.serverHello.encryptedClientHello != nil { // Unsolicited ECH extension should be rejected c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: unexpected ECH extension in serverHello") + return errors.New("tls: unexpected encrypted client hello extension in serverHello") } // The only HelloRetryRequest extensions we support are key_share and @@ -604,7 +604,7 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error { } if hs.echContext != nil && !hs.echContext.echRejected && encryptedExtensions.echRetryConfigs != nil { c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: server sent ECH retry configs after accepting ECH") + return errors.New("tls: server sent encrypted client hello retry configs after accepting encrypted client hello") } return nil diff --git a/handshake_messages.go b/handshake_messages.go index 823caff..fa00d7b 100644 --- a/handshake_messages.go +++ b/handshake_messages.go @@ -97,7 +97,7 @@ type clientHelloMsg struct { pskBinders [][]byte quicTransportParameters []byte encryptedClientHello []byte - // extensions are only populated on the server-side of a handshake + // extensions are only populated on the servers-ide of a handshake extensions []uint16 } @@ -662,6 +662,10 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { } m.pskBinders = append(m.pskBinders, binder) } + case extensionEncryptedClientHello: + if !extData.ReadBytes(&m.encryptedClientHello, len(extData)) { + return false + } default: // Ignore unknown extensions. continue diff --git a/handshake_messages_test.go b/handshake_messages_test.go index 2c360e6..e4112bf 100644 --- a/handshake_messages_test.go +++ b/handshake_messages_test.go @@ -232,6 +232,9 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value { if rand.Intn(10) > 5 { m.earlyData = true } + if rand.Intn(10) > 5 { + m.encryptedClientHello = randomBytes(rand.Intn(50)+1, rand) + } return reflect.ValueOf(m) } diff --git a/handshake_server.go b/handshake_server.go index 6fb1755..6fe9628 100644 --- a/handshake_server.go +++ b/handshake_server.go @@ -41,7 +41,7 @@ type serverHandshakeState struct { // serverHandshake performs a TLS handshake as a server. func (c *Conn) serverHandshake(ctx context.Context) error { - clientHello, err := c.readClientHello(ctx) + clientHello, ech, err := c.readClientHello(ctx) if err != nil { return err } @@ -51,6 +51,7 @@ func (c *Conn) serverHandshake(ctx context.Context) error { c: c, ctx: ctx, clientHello: clientHello, + echContext: ech, } return hs.handshake() } @@ -131,17 +132,27 @@ func (hs *serverHandshakeState) handshake() error { } // readClientHello reads a ClientHello message and selects the protocol version. -func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) { +func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, *echServerContext, error) { // clientHelloMsg is included in the transcript, but we haven't initialized // it yet. The respective handshake functions will record it themselves. msg, err := c.readHandshake(nil) if err != nil { - return nil, err + return nil, nil, err } clientHello, ok := msg.(*clientHelloMsg) if !ok { c.sendAlert(alertUnexpectedMessage) - return nil, unexpectedMessageError(clientHello, msg) + return nil, nil, unexpectedMessageError(clientHello, msg) + } + + // ECH processing has to be done before we do any other negotiation based on + // the contents of the client hello, since we may swap it out completely. + var ech *echServerContext + if len(clientHello.encryptedClientHello) != 0 { + clientHello, ech, err = c.processECHClientHello(clientHello) + if err != nil { + return nil, nil, err + } } var configForClient *Config @@ -150,7 +161,7 @@ func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) { chi := clientHelloInfo(ctx, c, clientHello) if configForClient, err = c.config.GetConfigForClient(chi); err != nil { c.sendAlert(alertInternalError) - return nil, err + return nil, nil, err } else if configForClient != nil { c.config = configForClient } @@ -164,18 +175,30 @@ func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) { c.vers, ok = c.config.mutualVersion(roleServer, clientVersions) if !ok { c.sendAlert(alertProtocolVersion) - return nil, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions) + return nil, nil, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions) } c.haveVers = true c.in.version = c.vers c.out.version = c.vers + // This check reflects some odd specification implied behavior. Client-facing servers + // are supposed to reject hellos with outer ECH and inner ECH that offers 1.2, but + // backend servers are allowed to accept hellos with inner ECH that offer 1.2, since + // they cannot expect client-facing servers to behave properly. Since we act as both + // a client-facing and backend server, we only enforce 1.3 being negotiated if we + // saw a hello with outer ECH first. The spec probably should've made this an error, + // but it didn't, and this matches the boringssl behavior. + if c.vers != VersionTLS13 && (ech != nil && !ech.inner) { + c.sendAlert(alertIllegalParameter) + return nil, nil, errors.New("tls: Encrypted Client Hello cannot be used pre-TLS 1.3") + } + if c.config.MinVersion == 0 && c.vers < VersionTLS12 { tls10server.Value() // ensure godebug is initialized tls10server.IncNonDefault() } - return clientHello, nil + return clientHello, ech, nil } func (hs *serverHandshakeState) processClientHello() error { diff --git a/handshake_server_test.go b/handshake_server_test.go index 01eae15..84b086f 100644 --- a/handshake_server_test.go +++ b/handshake_server_test.go @@ -54,12 +54,13 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa }() ctx := context.Background() conn := Server(s, serverConfig) - ch, err := conn.readClientHello(ctx) + ch, ech, err := conn.readClientHello(ctx) if conn.vers == VersionTLS13 { hs := serverHandshakeStateTLS13{ c: conn, ctx: ctx, clientHello: ch, + echContext: ech, } if err == nil { err = hs.processClientHello() @@ -1518,7 +1519,7 @@ func TestSNIGivenOnFailure(t *testing.T) { }() conn := Server(s, serverConfig) ctx := context.Background() - ch, err := conn.readClientHello(ctx) + ch, _, err := conn.readClientHello(ctx) hs := serverHandshakeState{ c: conn, ctx: ctx, diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index 64c6b13..76521d8 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -9,8 +9,10 @@ import ( "context" "crypto" "crypto/hmac" + "crypto/internal/fips140/hkdf" "crypto/internal/fips140/mlkem" "crypto/internal/fips140/tls13" + "crypto/internal/hpke" "crypto/rsa" "crypto/tls/internal/fips140tls" "errors" @@ -26,6 +28,18 @@ import ( // messages cause too much work in session ticket decryption attempts. const maxClientPSKIdentities = 5 +type echServerContext struct { + hpkeContext *hpke.Receipient + configID uint8 + ciphersuite echCipher + transcript hash.Hash + // inner indicates that the initial client_hello we recieved contained an + // encrypted_client_hello extension that indicated it was an "inner" hello. + // We don't do any additional processing of the hello in this case, so all + // fields above are unset. + inner bool +} + type serverHandshakeStateTLS13 struct { c *Conn ctx context.Context @@ -44,6 +58,7 @@ type serverHandshakeStateTLS13 struct { trafficSecret []byte // client_application_traffic_secret_0 transcript hash.Hash clientFinished []byte + echContext *echServerContext } func (hs *serverHandshakeStateTLS13) handshake() error { @@ -531,6 +546,22 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) selectedGroup: selectedGroup, } + if hs.echContext != nil { + // Compute the acceptance message. + helloRetryRequest.encryptedClientHello = make([]byte, 8) + confTranscript := cloneHash(hs.transcript, hs.suite.hash) + if err := transcriptMsg(helloRetryRequest, confTranscript); err != nil { + return nil, err + } + acceptConfirmation := tls13.ExpandLabel(hs.suite.hash.New, + hkdf.Extract(hs.suite.hash.New, hs.clientHello.random, nil), + "hrr ech accept confirmation", + confTranscript.Sum(nil), + 8, + ) + helloRetryRequest.encryptedClientHello = acceptConfirmation + } + if _, err := hs.c.writeHandshakeRecord(helloRetryRequest, hs.transcript); err != nil { return nil, err } @@ -551,6 +582,45 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) return nil, unexpectedMessageError(clientHello, msg) } + if hs.echContext != nil { + if len(clientHello.encryptedClientHello) == 0 { + c.sendAlert(alertMissingExtension) + return nil, errors.New("tls: second client hello missing encrypted client hello extension") + } + + echType, echCiphersuite, configID, encap, payload, err := parseECHExt(clientHello.encryptedClientHello) + if err != nil { + c.sendAlert(alertDecodeError) + return nil, errors.New("tls: client sent invalid encrypted client hello extension") + } + + if echType == outerECHExt && hs.echContext.inner || echType == innerECHExt && !hs.echContext.inner { + c.sendAlert(alertDecodeError) + return nil, errors.New("tls: unexpected switch in encrypted client hello extension type") + } + + if echType == outerECHExt { + if echCiphersuite != hs.echContext.ciphersuite || configID != hs.echContext.configID || len(encap) != 0 { + c.sendAlert(alertIllegalParameter) + return nil, errors.New("tls: second client hello encrypted client hello extension does not match") + } + + encodedInner, err := decryptECHPayload(hs.echContext.hpkeContext, clientHello.original, payload) + if err != nil { + c.sendAlert(alertDecryptError) + return nil, errors.New("tls: failed to decrypt second client hello encrypted client hello extension payload") + } + + echInner, err := decodeInnerClientHello(clientHello, encodedInner) + if err != nil { + c.sendAlert(alertIllegalParameter) + return nil, errors.New("tls: client sent invalid encrypted client hello extension") + } + + clientHello = echInner + } + } + if len(clientHello.keyShares) != 1 { c.sendAlert(alertIllegalParameter) return nil, errors.New("tls: client didn't send one key share in second ClientHello") @@ -638,9 +708,27 @@ func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool { func (hs *serverHandshakeStateTLS13) sendServerParameters() error { c := hs.c + if hs.echContext != nil { + copy(hs.hello.random[32-8:], make([]byte, 8)) + echTranscript := cloneHash(hs.transcript, hs.suite.hash) + echTranscript.Write(hs.clientHello.original) + if err := transcriptMsg(hs.hello, echTranscript); err != nil { + return err + } + // compute the acceptance message + acceptConfirmation := tls13.ExpandLabel(hs.suite.hash.New, + hkdf.Extract(hs.suite.hash.New, hs.clientHello.random, nil), + "ech accept confirmation", + echTranscript.Sum(nil), + 8, + ) + copy(hs.hello.random[32-8:], acceptConfirmation) + } + if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil { return err } + if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil { return err } @@ -691,6 +779,16 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error { encryptedExtensions.earlyData = hs.earlyData } + // If client sent ECH extension, but we didn't accept it, + // send retry configs, if available. + if len(hs.c.config.EncryptedClientHelloKeys) > 0 && len(hs.clientHello.encryptedClientHello) > 0 && hs.echContext == nil { + encryptedExtensions.echRetryConfigs, err = buildRetryConfigList(hs.c.config.EncryptedClientHelloKeys) + if err != nil { + c.sendAlert(alertInternalError) + return err + } + } + if _, err := hs.c.writeHandshakeRecord(encryptedExtensions, hs.transcript); err != nil { return err } diff --git a/tls_test.go b/tls_test.go index a6c0336..394d517 100644 --- a/tls_test.go +++ b/tls_test.go @@ -8,8 +8,10 @@ import ( "bytes" "context" "crypto" + "crypto/ecdh" "crypto/ecdsa" "crypto/elliptic" + "crypto/internal/hpke" "crypto/rand" "crypto/x509" "crypto/x509/pkix" @@ -29,6 +31,8 @@ import ( "strings" "testing" "time" + + "golang.org/x/crypto/cryptobyte" ) var rsaCertPEM = `-----BEGIN CERTIFICATE----- @@ -880,6 +884,10 @@ func TestCloneNonFuncFields(t *testing.T) { f.Set(reflect.ValueOf(RenegotiateOnceAsClient)) case "EncryptedClientHelloConfigList": f.Set(reflect.ValueOf([]byte{'x'})) + case "EncryptedClientHelloKeys": + f.Set(reflect.ValueOf([]EncryptedClientHelloKey{ + {Config: []byte{1}, PrivateKey: []byte{1}}, + })) case "mutex", "autoSessionTicketKeys", "sessionTicketKeys": continue // these are unexported fields that are handled separately default: @@ -2072,6 +2080,120 @@ func TestLargeCertMsg(t *testing.T) { }, } if _, _, err := testHandshake(t, clientConfig, serverConfig); err != nil { - t.Fatalf("unexpected failure :%s", err) + t.Fatalf("unexpected failure: %s", err) + } +} + +func TestECH(t *testing.T) { + k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + tmpl := &x509.Certificate{ + SerialNumber: big.NewInt(1), + DNSNames: []string{"public.example"}, + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(time.Hour), + } + publicCertDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k) + if err != nil { + t.Fatal(err) + } + publicCert, err := x509.ParseCertificate(publicCertDER) + if err != nil { + t.Fatal(err) + } + tmpl.DNSNames[0] = "secret.example" + secretCertDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k) + if err != nil { + t.Fatal(err) + } + secretCert, err := x509.ParseCertificate(secretCertDER) + if err != nil { + t.Fatal(err) + } + + marshalECHConfig := func(id uint8, pubKey []byte, publicName string, maxNameLen uint8) []byte { + builder := cryptobyte.NewBuilder(nil) + builder.AddUint16(extensionEncryptedClientHello) + builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) { + builder.AddUint8(id) + builder.AddUint16(hpke.DHKEM_X25519_HKDF_SHA256) // The only DHKEM we support + builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) { + builder.AddBytes(pubKey) + }) + builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) { + for _, aeadID := range sortedSupportedAEADs { + builder.AddUint16(hpke.KDF_HKDF_SHA256) // The only KDF we support + builder.AddUint16(aeadID) + } + }) + builder.AddUint8(maxNameLen) + builder.AddUint8LengthPrefixed(func(builder *cryptobyte.Builder) { + builder.AddBytes([]byte(publicName)) + }) + builder.AddUint16(0) // extensions + }) + + return builder.BytesOrPanic() + } + + echKey, err := ecdh.X25519().GenerateKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + + echConfig := marshalECHConfig(123, echKey.PublicKey().Bytes(), "public.example", 32) + + builder := cryptobyte.NewBuilder(nil) + builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) { + builder.AddBytes(echConfig) + }) + echConfigList := builder.BytesOrPanic() + + clientConfig, serverConfig := testConfig.Clone(), testConfig.Clone() + clientConfig.InsecureSkipVerify = false + clientConfig.Rand = rand.Reader + clientConfig.Time = nil + clientConfig.MinVersion = VersionTLS13 + clientConfig.ServerName = "secret.example" + clientConfig.RootCAs = x509.NewCertPool() + clientConfig.RootCAs.AddCert(secretCert) + clientConfig.RootCAs.AddCert(publicCert) + clientConfig.EncryptedClientHelloConfigList = echConfigList + serverConfig.InsecureSkipVerify = false + serverConfig.Rand = rand.Reader + serverConfig.Time = nil + serverConfig.MinVersion = VersionTLS13 + serverConfig.ServerName = "public.example" + serverConfig.Certificates = []Certificate{ + {Certificate: [][]byte{publicCertDER}, PrivateKey: k}, + {Certificate: [][]byte{secretCertDER}, PrivateKey: k}, + } + serverConfig.EncryptedClientHelloKeys = []EncryptedClientHelloKey{ + {Config: echConfig, PrivateKey: echKey.Bytes(), SendAsRetry: true}, + } + + ss, cs, err := testHandshake(t, clientConfig, serverConfig) + if err != nil { + t.Fatalf("unexpected failure: %s", err) + } + if !ss.ECHAccepted { + t.Fatal("server ConnectionState shows ECH not accepted") + } + if !cs.ECHAccepted { + t.Fatal("client ConnectionState shows ECH not accepted") + } + if cs.ServerName != "secret.example" || ss.ServerName != "secret.example" { + t.Fatalf("unexpected ConnectionState.ServerName, want %q, got server:%q, client: %q", "secret.example", ss.ServerName, cs.ServerName) + } + if len(cs.VerifiedChains) != 1 { + t.Fatal("unexpect number of certificate chains") + } + if len(cs.VerifiedChains[0]) != 1 { + t.Fatal("unexpect number of certificates") + } + if !cs.VerifiedChains[0][0].Equal(secretCert) { + t.Fatal("unexpected certificate") } } From 4cb059fbbf401fceb54b50fbee319e8ef96f64a1 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Wed, 20 Nov 2024 20:09:50 -0500 Subject: [PATCH 25/34] crypto/tls: test with FIPS 140-3 TLS mode For tests that are interested in testing the difference between TLS in FIPS 140-3 required mode or otherwise two new helpers are introduced, runWithFIPSEnabled and runWithFIPSDisabled. They take care of forcing the correct TLS FIPS 140-3 state regardless of the overal GODEBUG=fips state, and restoring it afterwards. For the tests that use features or test data not appropriate for TLS in FIPS 140-3 required mode we add skips. For some tests we can make them appropriate for both TLS FIPS 140-3 required or not by tweaking some parameters that weren't important to the subject under test, but would otherwise preclude TLS FIPS 140-3 required mode (e.g. because they used TLS 1.0 when the test could use TLS 1.2 instead). For others, switching test certificates to a RSA 2048 hierarchy is sufficient. We avoid regenerating the existing RSA 1024 certs as 2048 since it would invalidate recorded static flow data. Tests that rely on static message flows (primarily the client and server handshake) tests are skipped due to FIPS mode being non-deterministic and inappropriate for this style of testing. Change-Id: I311f3828dac890bb3ff8ebda6ed73d50f0797110 Reviewed-on: https://go-review.googlesource.com/c/go/+/629736 Reviewed-by: Roland Shoemaker Reviewed-by: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- auth_test.go | 6 ++ bogo_shim_test.go | 1 + conn_test.go | 4 ++ fips_test.go | 116 +++++++++++++++++++++------------------ handshake_client_test.go | 90 +++++++++++++++++++----------- handshake_server_test.go | 87 +++++++++++++++++------------ handshake_test.go | 9 +++ tls_test.go | 43 +++++++++++++++ 8 files changed, 238 insertions(+), 118 deletions(-) diff --git a/auth_test.go b/auth_test.go index c23d93f..9036f4c 100644 --- a/auth_test.go +++ b/auth_test.go @@ -6,6 +6,7 @@ package tls import ( "crypto" + "crypto/tls/internal/fips140tls" "testing" ) @@ -57,6 +58,11 @@ func TestSignatureSelection(t *testing.T) { } for testNo, test := range tests { + if fips140tls.Required() && (test.expectedHash == crypto.SHA1 || test.expectedSigAlg == Ed25519) { + t.Logf("skipping test[%d] - not compatible with TLS FIPS mode", testNo) + continue + } + sigAlg, err := selectSignatureScheme(test.tlsVersion, test.cert, test.peerSigAlgs) if err != nil { t.Errorf("test[%d]: unexpected selectSignatureScheme error: %v", testNo, err) diff --git a/bogo_shim_test.go b/bogo_shim_test.go index b294608..561f0a6 100644 --- a/bogo_shim_test.go +++ b/bogo_shim_test.go @@ -406,6 +406,7 @@ func TestBogoSuite(t *testing.T) { if testenv.Builder() != "" && runtime.GOOS == "windows" { t.Skip("#66913: windows network connections are flakey on builders") } + skipFIPS(t) // In order to make Go test caching work as expected, we stat the // bogo_config.json file, so that the Go testing hooks know that it is diff --git a/conn_test.go b/conn_test.go index 5e090a0..5fd48d6 100644 --- a/conn_test.go +++ b/conn_test.go @@ -230,6 +230,8 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) { } func TestDynamicRecordSizingWithStreamCipher(t *testing.T) { + skipFIPS(t) // No RC4 in FIPS mode. + config := testConfig.Clone() config.MaxVersion = VersionTLS12 config.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA} @@ -237,6 +239,8 @@ func TestDynamicRecordSizingWithStreamCipher(t *testing.T) { } func TestDynamicRecordSizingWithCBC(t *testing.T) { + skipFIPS(t) // No CBC cipher suites in defaultCipherSuitesFIPS. + config := testConfig.Clone() config.MaxVersion = VersionTLS12 config.CipherSuites = []uint16{TLS_RSA_WITH_AES_256_CBC_SHA} diff --git a/fips_test.go b/fips_test.go index b28b6f4..5447aa1 100644 --- a/fips_test.go +++ b/fips_test.go @@ -9,7 +9,6 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/rsa" - "crypto/tls/internal/fips140tls" "crypto/x509" "crypto/x509/pkix" "encoding/pem" @@ -73,14 +72,14 @@ func TestFIPSServerProtocolVersion(t *testing.T) { }) } - test(t, "VersionTLS10", VersionTLS10, "") - test(t, "VersionTLS11", VersionTLS11, "") - test(t, "VersionTLS12", VersionTLS12, "") - test(t, "VersionTLS13", VersionTLS13, "") + runWithFIPSDisabled(t, func(t *testing.T) { + test(t, "VersionTLS10", VersionTLS10, "") + test(t, "VersionTLS11", VersionTLS11, "") + test(t, "VersionTLS12", VersionTLS12, "") + test(t, "VersionTLS13", VersionTLS13, "") + }) - t.Run("fips140tls", func(t *testing.T) { - fips140tls.Force() - defer fips140tls.TestingOnlyAbandon() + runWithFIPSEnabled(t, func(t *testing.T) { test(t, "VersionTLS10", VersionTLS10, "supported versions") test(t, "VersionTLS11", VersionTLS11, "supported versions") test(t, "VersionTLS12", VersionTLS12, "") @@ -168,10 +167,11 @@ func TestFIPSServerCipherSuites(t *testing.T) { clientHello.supportedVersions = []uint16{VersionTLS13} } - testClientHello(t, serverConfig, clientHello) - t.Run("fips140tls", func(t *testing.T) { - fips140tls.Force() - defer fips140tls.TestingOnlyAbandon() + runWithFIPSDisabled(t, func(t *testing.T) { + testClientHello(t, serverConfig, clientHello) + }) + + runWithFIPSEnabled(t, func(t *testing.T) { msg := "" if !isFIPSCipherSuite(id) { msg = "no cipher suite supported by both client and server" @@ -194,14 +194,15 @@ func TestFIPSServerCurves(t *testing.T) { // x25519Kyber768Draft00 is not supported standalone. clientConfig.CurvePreferences = append(clientConfig.CurvePreferences, X25519) } - if _, _, err := testHandshake(t, clientConfig, serverConfig); err != nil { - t.Fatalf("got error: %v, expected success", err) - } - // With fips140tls forced, bad curves should be rejected. - t.Run("fips140tls", func(t *testing.T) { - fips140tls.Force() - defer fips140tls.TestingOnlyAbandon() + runWithFIPSDisabled(t, func(t *testing.T) { + if _, _, err := testHandshake(t, clientConfig, serverConfig); err != nil { + t.Fatalf("got error: %v, expected success", err) + } + }) + + // With fipstls forced, bad curves should be rejected. + runWithFIPSEnabled(t, func(t *testing.T) { _, _, err := testHandshake(t, clientConfig, serverConfig) if err != nil && isFIPSCurve(curveid) { t.Fatalf("got error: %v, expected success", err) @@ -244,8 +245,8 @@ func TestFIPSServerSignatureAndHash(t *testing.T) { switch sigType { case signaturePKCS1v15, signatureRSAPSS: serverConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256} - serverConfig.Certificates[0].Certificate = [][]byte{testRSA2048Certificate} - serverConfig.Certificates[0].PrivateKey = testRSA2048PrivateKey + serverConfig.Certificates[0].Certificate = [][]byte{testRSAPSS2048Certificate} + serverConfig.Certificates[0].PrivateKey = testRSAPSS2048PrivateKey case signatureEd25519: serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256} serverConfig.Certificates[0].Certificate = [][]byte{testEd25519Certificate} @@ -260,15 +261,15 @@ func TestFIPSServerSignatureAndHash(t *testing.T) { // 1.3, and the ECDSA ones bind to the curve used. serverConfig.MaxVersion = VersionTLS12 - clientErr, serverErr := fipsHandshake(t, testConfig, serverConfig) - if clientErr != nil { - t.Fatalf("expected handshake with %#x to succeed; client error: %v; server error: %v", sigHash, clientErr, serverErr) - } + runWithFIPSDisabled(t, func(t *testing.T) { + clientErr, serverErr := fipsHandshake(t, testConfig, serverConfig) + if clientErr != nil { + t.Fatalf("expected handshake with %#x to succeed; client error: %v; server error: %v", sigHash, clientErr, serverErr) + } + }) - // With fips140tls forced, bad curves should be rejected. - t.Run("fips140tls", func(t *testing.T) { - fips140tls.Force() - defer fips140tls.TestingOnlyAbandon() + // With fipstls forced, bad curves should be rejected. + runWithFIPSEnabled(t, func(t *testing.T) { clientErr, _ := fipsHandshake(t, testConfig, serverConfig) if isFIPSSignatureScheme(sigHash) { if clientErr != nil { @@ -285,10 +286,12 @@ func TestFIPSServerSignatureAndHash(t *testing.T) { } func TestFIPSClientHello(t *testing.T) { + runWithFIPSEnabled(t, testFIPSClientHello) +} + +func testFIPSClientHello(t *testing.T) { // Test that no matter what we put in the client config, // the client does not offer non-FIPS configurations. - fips140tls.Force() - defer fips140tls.TestingOnlyAbandon() c, s := net.Pipe() defer c.Close() @@ -423,12 +426,16 @@ func TestFIPSCertAlgs(t *testing.T) { // exhaustive test with computed answers. r1pool := x509.NewCertPool() r1pool.AddCert(R1.cert) - testServerCert(t, "basic", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true) - testClientCert(t, "basic (client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true) - fips140tls.Force() - testServerCert(t, "basic (fips)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false) - testClientCert(t, "basic (fips, client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false) - fips140tls.TestingOnlyAbandon() + + runWithFIPSDisabled(t, func(t *testing.T) { + testServerCert(t, "basic", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true) + testClientCert(t, "basic (client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true) + }) + + runWithFIPSEnabled(t, func(t *testing.T) { + testServerCert(t, "basic (fips)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false) + testClientCert(t, "basic (fips, client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false) + }) if t.Failed() { t.Fatal("basic test failed, skipping exhaustive test") @@ -488,12 +495,16 @@ func TestFIPSCertAlgs(t *testing.T) { addRoot(r&1, R1) addRoot(r&2, R2) rootName = rootName[1:] // strip leading comma - testServerCert(t, listName+"->"+rootName[1:], pool, leaf.key, list, shouldVerify) - testClientCert(t, listName+"->"+rootName[1:]+"(client cert)", pool, leaf.key, list, shouldVerify) - fips140tls.Force() - testServerCert(t, listName+"->"+rootName[1:]+" (fips)", pool, leaf.key, list, shouldVerifyFIPS) - testClientCert(t, listName+"->"+rootName[1:]+" (fips, client cert)", pool, leaf.key, list, shouldVerifyFIPS) - fips140tls.TestingOnlyAbandon() + + runWithFIPSDisabled(t, func(t *testing.T) { + testServerCert(t, listName+"->"+rootName[1:], pool, leaf.key, list, shouldVerify) + testClientCert(t, listName+"->"+rootName[1:]+"(client cert)", pool, leaf.key, list, shouldVerify) + }) + + runWithFIPSEnabled(t, func(t *testing.T) { + testServerCert(t, listName+"->"+rootName[1:]+" (fips)", pool, leaf.key, list, shouldVerifyFIPS) + testClientCert(t, listName+"->"+rootName[1:]+" (fips, client cert)", pool, leaf.key, list, shouldVerifyFIPS) + }) } } } @@ -589,13 +600,12 @@ func fipsCert(t *testing.T, name string, key interface{}, parent *fipsCertificat t.Fatal(err) } - fips140tls.Force() - defer fips140tls.TestingOnlyAbandon() - fipsOK := mode&fipsCertFIPSOK != 0 - if fipsAllowCert(cert) != fipsOK { - t.Errorf("fipsAllowCert(cert with %s key) = %v, want %v", desc, !fipsOK, fipsOK) - } + runWithFIPSEnabled(t, func(t *testing.T) { + if fipsAllowCert(cert) != fipsOK { + t.Errorf("fipsAllowCert(cert with %s key) = %v, want %v", desc, !fipsOK, fipsOK) + } + }) return &fipsCertificate{name, org, parentOrg, der, cert, key, fipsOK} } @@ -603,8 +613,8 @@ func fipsCert(t *testing.T, name string, key interface{}, parent *fipsCertificat // A self-signed test certificate with an RSA key of size 2048, for testing // RSA-PSS with SHA512. SAN of example.golang. var ( - testRSA2048Certificate []byte - testRSA2048PrivateKey *rsa.PrivateKey + testRSAPSS2048Certificate []byte + testRSAPSS2048PrivateKey *rsa.PrivateKey ) func init() { @@ -628,7 +638,7 @@ aEjosRZNJv1nDEl5qG9XN3FC9zb5FrGSFmTTUvR4f4tUHr7wifNSS2dtgQ6+jU6f m9o6fukaP7t5VyOXuV7FIO/Hdg2lqW+xU1LowZpVd6ANZ5rAZXtMhWe3+mjfFtju TAnR -----RAQ PREGVSVPNGR-----`))) - testRSA2048Certificate = block.Bytes + testRSAPSS2048Certificate = block.Bytes block, _ = pem.Decode(obscuretestdata.Rot13([]byte(` -----ORTVA EFN CEVINGR XRL----- @@ -659,7 +669,7 @@ bBegiZqey6hcl9Um4OWQ3SKjISvCSR7wdrAdv0S21ivYkOCZZQ3HBQS6YY5RlYvE 9I4kIZF8XKkit7ekfhdmZCfpIvnJHY6JAIOufQ2+92qUkFKmm5RWXD== -----RAQ EFN CEVINGR XRL-----`))) var err error - testRSA2048PrivateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes) + testRSAPSS2048PrivateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { panic(err) } diff --git a/handshake_client_test.go b/handshake_client_test.go index 2aded1a..bb164bb 100644 --- a/handshake_client_test.go +++ b/handshake_client_test.go @@ -11,6 +11,7 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/rsa" + "crypto/tls/internal/fips140tls" "crypto/x509" "crypto/x509/pkix" "encoding/base64" @@ -848,13 +849,16 @@ func testResumption(t *testing.T, version uint16) { if testing.Short() { t.Skip("skipping in -short mode") } + + // Note: using RSA 2048 test certificates because they are compatible with FIPS mode. + testCertificates := []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}} serverConfig := &Config{ MaxVersion: version, - CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, - Certificates: testConfig.Certificates, + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, + Certificates: testCertificates, } - issuer, err := x509.ParseCertificate(testRSACertificateIssuer) + issuer, err := x509.ParseCertificate(testRSA2048CertificateIssuer) if err != nil { panic(err) } @@ -864,7 +868,7 @@ func testResumption(t *testing.T, version uint16) { clientConfig := &Config{ MaxVersion: version, - CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, ClientSessionCache: NewLRUClientSessionCache(32), RootCAs: rootCAs, ServerName: "example.golang", @@ -982,8 +986,8 @@ func testResumption(t *testing.T, version uint16) { // before the serverConfig is used works. serverConfig = &Config{ MaxVersion: version, - CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, - Certificates: testConfig.Certificates, + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, + Certificates: testCertificates, } serverConfig.SetSessionTicketKeys([][32]byte{key2}) @@ -992,7 +996,7 @@ func testResumption(t *testing.T, version uint16) { // In TLS 1.3, cross-cipher suite resumption is allowed as long as the KDF // hash matches. Also, Config.CipherSuites does not apply to TLS 1.3. if version != VersionTLS13 { - clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA} + clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384} testResumeState("DifferentCipherSuite", false) testResumeState("DifferentCipherSuiteRecovers", true) } @@ -1008,7 +1012,7 @@ func testResumption(t *testing.T, version uint16) { // Use a different curve than the client to force a HelloRetryRequest. CurvePreferences: []CurveID{CurveP521, CurveP384, CurveP256}, MaxVersion: version, - Certificates: testConfig.Certificates, + Certificates: testCertificates, } testResumeState("InitialHandshake", false) testResumeState("WithHelloRetryRequest", true) @@ -1016,8 +1020,8 @@ func testResumption(t *testing.T, version uint16) { // Reset serverConfig back. serverConfig = &Config{ MaxVersion: version, - CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, - Certificates: testConfig.Certificates, + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, + Certificates: testCertificates, } } @@ -1272,7 +1276,7 @@ func TestServerSelectingUnconfiguredApplicationProtocol(t *testing.T) { go func() { client := Client(c, &Config{ ServerName: "foo", - CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, NextProtos: []string{"http", "something-else"}, }) errChan <- client.Handshake() @@ -1292,7 +1296,7 @@ func TestServerSelectingUnconfiguredApplicationProtocol(t *testing.T) { serverHello := &serverHelloMsg{ vers: VersionTLS12, random: make([]byte, 32), - cipherSuite: TLS_RSA_WITH_AES_128_GCM_SHA256, + cipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, alpnProtocol: "how-about-this", } serverHelloBytes := mustMarshal(t, serverHello) @@ -1308,7 +1312,7 @@ func TestServerSelectingUnconfiguredApplicationProtocol(t *testing.T) { s.Close() if err := <-errChan; !strings.Contains(err.Error(), "server selected unadvertised ALPN protocol") { - t.Fatalf("Expected error about unconfigured cipher suite but got %q", err) + t.Fatalf("Expected error about unconfigured ALPN protocol but got %q", err) } } @@ -1724,7 +1728,10 @@ func testVerifyConnection(t *testing.T, version uint16) { }, } for _, test := range tests { - issuer, err := x509.ParseCertificate(testRSACertificateIssuer) + // Note: using RSA 2048 test certificates because they are compatible with FIPS mode. + testCertificates := []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}} + + issuer, err := x509.ParseCertificate(testRSA2048CertificateIssuer) if err != nil { panic(err) } @@ -1735,7 +1742,7 @@ func testVerifyConnection(t *testing.T, version uint16) { serverConfig := &Config{ MaxVersion: version, - Certificates: []Certificate{testConfig.Certificates[0]}, + Certificates: testCertificates, ClientCAs: rootCAs, NextProtos: []string{"protocol1"}, } @@ -1748,7 +1755,7 @@ func testVerifyConnection(t *testing.T, version uint16) { ClientSessionCache: NewLRUClientSessionCache(32), RootCAs: rootCAs, ServerName: "example.golang", - Certificates: []Certificate{testConfig.Certificates[0]}, + Certificates: testCertificates, NextProtos: []string{"protocol1"}, } test.configureClient(clientConfig, &clientCalled) @@ -1783,7 +1790,8 @@ func TestVerifyPeerCertificate(t *testing.T) { } func testVerifyPeerCertificate(t *testing.T, version uint16) { - issuer, err := x509.ParseCertificate(testRSACertificateIssuer) + // Note: using RSA 2048 test certificates because they are compatible with FIPS mode. + issuer, err := x509.ParseCertificate(testRSA2048CertificateIssuer) if err != nil { panic(err) } @@ -2041,8 +2049,8 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) { config.Time = now config.MaxVersion = version config.Certificates = make([]Certificate, 1) - config.Certificates[0].Certificate = [][]byte{testRSACertificate} - config.Certificates[0].PrivateKey = testRSAPrivateKey + config.Certificates[0].Certificate = [][]byte{testRSA2048Certificate} + config.Certificates[0].PrivateKey = testRSA2048PrivateKey config.Certificates[0].SignedCertificateTimestamps = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")} config.Certificates[0].OCSPStaple = []byte("dummy ocsp") test.configureServer(config, &serverCalled) @@ -2053,6 +2061,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) { }() config := testConfig.Clone() + config.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}} config.ServerName = "example.golang" config.RootCAs = rootCAs config.Time = now @@ -2336,8 +2345,8 @@ var getClientCertificateTests = []struct { panic("empty AcceptableCAs") } cert := &Certificate{ - Certificate: [][]byte{testRSACertificate}, - PrivateKey: testRSAPrivateKey, + Certificate: [][]byte{testRSA2048Certificate}, + PrivateKey: testRSA2048PrivateKey, } return cert, nil } @@ -2357,13 +2366,15 @@ func TestGetClientCertificate(t *testing.T) { } func testGetClientCertificate(t *testing.T, version uint16) { - issuer, err := x509.ParseCertificate(testRSACertificateIssuer) + // Note: using RSA 2048 test certificates because they are compatible with FIPS mode. + issuer, err := x509.ParseCertificate(testRSA2048CertificateIssuer) if err != nil { panic(err) } for i, test := range getClientCertificateTests { serverConfig := testConfig.Clone() + serverConfig.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}} serverConfig.ClientAuth = VerifyClientCertIfGiven serverConfig.RootCAs = x509.NewCertPool() serverConfig.RootCAs.AddCert(issuer) @@ -2372,10 +2383,17 @@ func testGetClientCertificate(t *testing.T, version uint16) { serverConfig.MaxVersion = version clientConfig := testConfig.Clone() + clientConfig.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}} clientConfig.MaxVersion = version test.setup(clientConfig, serverConfig) + // TLS 1.1 isn't available for FIPS required + if fips140tls.Required() && clientConfig.MaxVersion == VersionTLS11 { + t.Logf("skipping test %d for FIPS mode", i) + continue + } + type serverResult struct { cs ConnectionState err error @@ -2514,11 +2532,15 @@ func TestDowngradeCanary(t *testing.T) { if err := testDowngradeCanary(t, VersionTLS12, VersionTLS12); err != nil { t.Errorf("client didn't ignore expected TLS 1.2 canary") } - if err := testDowngradeCanary(t, VersionTLS11, VersionTLS11); err != nil { - t.Errorf("client unexpectedly reacted to a canary in TLS 1.1") - } - if err := testDowngradeCanary(t, VersionTLS10, VersionTLS10); err != nil { - t.Errorf("client unexpectedly reacted to a canary in TLS 1.0") + if !fips140tls.Required() { + if err := testDowngradeCanary(t, VersionTLS11, VersionTLS11); err != nil { + t.Errorf("client unexpectedly reacted to a canary in TLS 1.1") + } + if err := testDowngradeCanary(t, VersionTLS10, VersionTLS10); err != nil { + t.Errorf("client unexpectedly reacted to a canary in TLS 1.0") + } + } else { + t.Logf("skiping TLS 1.1 and TLS 1.0 downgrade canary checks in FIPS mode") } } @@ -2528,7 +2550,8 @@ func TestResumptionKeepsOCSPAndSCT(t *testing.T) { } func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) { - issuer, err := x509.ParseCertificate(testRSACertificateIssuer) + // Note: using RSA 2048 test certificates because they are compatible with FIPS mode. + issuer, err := x509.ParseCertificate(testRSA2048CertificateIssuer) if err != nil { t.Fatalf("failed to parse test issuer") } @@ -2541,6 +2564,7 @@ func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) { RootCAs: roots, } serverConfig := testConfig.Clone() + serverConfig.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}} serverConfig.MaxVersion = ver serverConfig.Certificates[0].OCSPStaple = []byte{1, 2, 3} serverConfig.Certificates[0].SignedCertificateTimestamps = [][]byte{{4, 5, 6}} @@ -2675,11 +2699,15 @@ func testTLS13OnlyClientHelloCipherSuite(t *testing.T, ciphers []uint16) { serverConfig := &Config{ Certificates: testConfig.Certificates, GetConfigForClient: func(chi *ClientHelloInfo) (*Config, error) { - if len(chi.CipherSuites) != len(defaultCipherSuitesTLS13NoAES) { + expectedCiphersuites := defaultCipherSuitesTLS13NoAES + if fips140tls.Required() { + expectedCiphersuites = defaultCipherSuitesTLS13FIPS + } + if len(chi.CipherSuites) != len(expectedCiphersuites) { t.Errorf("only TLS 1.3 suites should be advertised, got=%x", chi.CipherSuites) } else { - for i := range defaultCipherSuitesTLS13NoAES { - if want, got := defaultCipherSuitesTLS13NoAES[i], chi.CipherSuites[i]; want != got { + for i := range expectedCiphersuites { + if want, got := expectedCiphersuites[i], chi.CipherSuites[i]; want != got { t.Errorf("cipher at index %d does not match, want=%x, got=%x", i, want, got) } } diff --git a/handshake_server_test.go b/handshake_server_test.go index 84b086f..17453eb 100644 --- a/handshake_server_test.go +++ b/handshake_server_test.go @@ -11,6 +11,7 @@ import ( "crypto/ecdh" "crypto/elliptic" "crypto/rand" + "crypto/tls/internal/fips140tls" "crypto/x509" "encoding/pem" "errors" @@ -119,7 +120,7 @@ func TestRejectBadProtocolVersion(t *testing.T) { func TestNoSuiteOverlap(t *testing.T) { clientHello := &clientHelloMsg{ - vers: VersionTLS10, + vers: VersionTLS12, random: make([]byte, 32), cipherSuites: []uint16{0xff00}, compressionMethods: []uint8{compressionNone}, @@ -129,9 +130,9 @@ func TestNoSuiteOverlap(t *testing.T) { func TestNoCompressionOverlap(t *testing.T) { clientHello := &clientHelloMsg{ - vers: VersionTLS10, + vers: VersionTLS12, random: make([]byte, 32), - cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, compressionMethods: []uint8{0xff}, } testClientHelloFailure(t, testConfig, clientHello, "client does not support uncompressed connections") @@ -139,7 +140,7 @@ func TestNoCompressionOverlap(t *testing.T) { func TestNoRC4ByDefault(t *testing.T) { clientHello := &clientHelloMsg{ - vers: VersionTLS10, + vers: VersionTLS12, random: make([]byte, 32), cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, compressionMethods: []uint8{compressionNone}, @@ -163,9 +164,9 @@ func TestDontSelectECDSAWithRSAKey(t *testing.T) { // Test that, even when both sides support an ECDSA cipher suite, it // won't be selected if the server's private key doesn't support it. clientHello := &clientHelloMsg{ - vers: VersionTLS10, + vers: VersionTLS12, random: make([]byte, 32), - cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, + cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384}, compressionMethods: []uint8{compressionNone}, supportedCurves: []CurveID{CurveP256}, supportedPoints: []uint8{pointFormatUncompressed}, @@ -189,9 +190,9 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) { // Test that, even when both sides support an RSA cipher suite, it // won't be selected if the server's private key doesn't support it. clientHello := &clientHelloMsg{ - vers: VersionTLS10, + vers: VersionTLS12, random: make([]byte, 32), - cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, + cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, compressionMethods: []uint8{compressionNone}, supportedCurves: []CurveID{CurveP256}, supportedPoints: []uint8{pointFormatUncompressed}, @@ -211,6 +212,8 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) { } func TestRenegotiationExtension(t *testing.T) { + skipFIPS(t) // #70505 + clientHello := &clientHelloMsg{ vers: VersionTLS12, compressionMethods: []uint8{compressionNone}, @@ -263,6 +266,8 @@ func TestRenegotiationExtension(t *testing.T) { } func TestTLS12OnlyCipherSuites(t *testing.T) { + skipFIPS(t) // No TLS 1.1 in FIPS mode. + // Test that a Server doesn't select a TLS 1.2-only cipher suite when // the client negotiates TLS 1.1. clientHello := &clientHelloMsg{ @@ -324,13 +329,18 @@ func TestTLSPointFormats(t *testing.T) { supportedPoints []uint8 wantSupportedPoints bool }{ - {"ECC", []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, []CurveID{CurveP256}, []uint8{pointFormatUncompressed}, true}, - {"ECC without ec_point_format", []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, []CurveID{CurveP256}, nil, false}, - {"ECC with extra values", []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, []CurveID{CurveP256}, []uint8{13, 37, pointFormatUncompressed, 42}, true}, + {"ECC", []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, []CurveID{CurveP256}, []uint8{pointFormatUncompressed}, true}, + {"ECC without ec_point_format", []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, []CurveID{CurveP256}, nil, false}, + {"ECC with extra values", []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, []CurveID{CurveP256}, []uint8{13, 37, pointFormatUncompressed, 42}, true}, {"RSA", []uint16{TLS_RSA_WITH_AES_256_GCM_SHA384}, nil, nil, false}, {"RSA with ec_point_format", []uint16{TLS_RSA_WITH_AES_256_GCM_SHA384}, nil, []uint8{pointFormatUncompressed}, false}, } for _, tt := range tests { + // The RSA subtests should be enabled for FIPS 140 required mode: #70505 + if strings.HasPrefix(tt.name, "RSA") && fips140tls.Required() { + t.Logf("skipping in FIPS mode.") + continue + } t.Run(tt.name, func(t *testing.T) { clientHello := &clientHelloMsg{ vers: VersionTLS12, @@ -344,7 +354,9 @@ func TestTLSPointFormats(t *testing.T) { c, s := localPipe(t) replyChan := make(chan any) go func() { - cli := Client(c, testConfig) + clientConfig := testConfig.Clone() + clientConfig.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}} + cli := Client(c, clientConfig) cli.vers = clientHello.vers if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil { testFatal(t, err) @@ -357,9 +369,10 @@ func TestTLSPointFormats(t *testing.T) { replyChan <- reply } }() - config := testConfig.Clone() - config.CipherSuites = clientHello.cipherSuites - Server(s, config).Handshake() + serverConfig := testConfig.Clone() + serverConfig.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}} + serverConfig.CipherSuites = clientHello.cipherSuites + Server(s, serverConfig).Handshake() s.Close() reply := <-replyChan if err, ok := reply.(error); ok { @@ -434,6 +447,8 @@ func TestVersion(t *testing.T) { } func TestCipherSuitePreference(t *testing.T) { + skipFIPS(t) // No RC4 or CHACHA20_POLY1305 in FIPS mode. + serverConfig := &Config{ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, @@ -502,11 +517,11 @@ func TestCrossVersionResume(t *testing.T) { func testCrossVersionResume(t *testing.T, version uint16) { serverConfig := &Config{ - CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, Certificates: testConfig.Certificates, } clientConfig := &Config{ - CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, InsecureSkipVerify: true, ClientSessionCache: NewLRUClientSessionCache(1), ServerName: "servername", @@ -927,14 +942,14 @@ func TestHandshakeServerKeySharePreference(t *testing.T) { // TestHandshakeServerUnsupportedKeyShare tests a client that sends a key share // that's not in the supported groups list. func TestHandshakeServerUnsupportedKeyShare(t *testing.T) { - pk, _ := ecdh.X25519().GenerateKey(rand.Reader) + pk, _ := ecdh.P384().GenerateKey(rand.Reader) clientHello := &clientHelloMsg{ vers: VersionTLS12, random: make([]byte, 32), supportedVersions: []uint16{VersionTLS13}, - cipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256}, + cipherSuites: []uint16{TLS_AES_128_GCM_SHA256}, compressionMethods: []uint8{compressionNone}, - keyShares: []keyShare{{group: X25519, data: pk.PublicKey().Bytes()}}, + keyShares: []keyShare{{group: CurveP384, data: pk.PublicKey().Bytes()}}, supportedCurves: []CurveID{CurveP256}, } testClientHelloFailure(t, testConfig, clientHello, "client sent key share for group it does not support") @@ -1081,16 +1096,16 @@ func TestHandshakeServerGetCertificateExtensions(t *testing.T) { testVersions := []uint16{VersionTLS12, VersionTLS13} for _, vers := range testVersions { t.Run(fmt.Sprintf("TLS version %04x", vers), func(t *testing.T) { - pk, _ := ecdh.X25519().GenerateKey(rand.Reader) + pk, _ := ecdh.P256().GenerateKey(rand.Reader) clientHello := &clientHelloMsg{ vers: vers, random: make([]byte, 32), - cipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256}, + cipherSuites: []uint16{TLS_AES_128_GCM_SHA256}, compressionMethods: []uint8{compressionNone}, serverName: "test", - keyShares: []keyShare{{group: X25519, data: pk.PublicKey().Bytes()}}, - supportedCurves: []CurveID{X25519}, - supportedSignatureAlgorithms: []SignatureScheme{Ed25519}, + keyShares: []keyShare{{group: CurveP256, data: pk.PublicKey().Bytes()}}, + supportedCurves: []CurveID{CurveP256}, + supportedSignatureAlgorithms: []SignatureScheme{ECDSAWithP256AndSHA256}, } // the clientHelloMsg initialized just above is serialized with @@ -1139,9 +1154,9 @@ func TestHandshakeServerSNIGetCertificateError(t *testing.T) { } clientHello := &clientHelloMsg{ - vers: VersionTLS10, + vers: VersionTLS12, random: make([]byte, 32), - cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, compressionMethods: []uint8{compressionNone}, serverName: "test", } @@ -1160,9 +1175,9 @@ func TestHandshakeServerEmptyCertificates(t *testing.T) { serverConfig.Certificates = nil clientHello := &clientHelloMsg{ - vers: VersionTLS10, + vers: VersionTLS12, random: make([]byte, 32), - cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, compressionMethods: []uint8{compressionNone}, } testClientHelloFailure(t, serverConfig, clientHello, errMsg) @@ -1172,9 +1187,9 @@ func TestHandshakeServerEmptyCertificates(t *testing.T) { serverConfig.GetCertificate = nil clientHello = &clientHelloMsg{ - vers: VersionTLS10, + vers: VersionTLS12, random: make([]byte, 32), - cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, compressionMethods: []uint8{compressionNone}, } testClientHelloFailure(t, serverConfig, clientHello, "no certificates") @@ -1497,9 +1512,9 @@ func TestSNIGivenOnFailure(t *testing.T) { const expectedServerName = "test.testing" clientHello := &clientHelloMsg{ - vers: VersionTLS10, + vers: VersionTLS12, random: make([]byte, 32), - cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, compressionMethods: []uint8{compressionNone}, serverName: expectedServerName, } @@ -1755,7 +1770,7 @@ T+E0J8wlH24pgwQHzy7Ko2qLwn1b5PW8ecrlvP1g func TestMultipleCertificates(t *testing.T) { clientConfig := testConfig.Clone() - clientConfig.CipherSuites = []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256} + clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256} clientConfig.MaxVersion = VersionTLS12 serverConfig := testConfig.Clone() @@ -1777,6 +1792,8 @@ func TestMultipleCertificates(t *testing.T) { } func TestAESCipherReordering(t *testing.T) { + skipFIPS(t) // No CHACHA20_POLY1305 for FIPS. + currentAESSupport := hasAESGCMHardwareSupport defer func() { hasAESGCMHardwareSupport = currentAESSupport }() @@ -1920,6 +1937,8 @@ func TestAESCipherReordering(t *testing.T) { } func TestAESCipherReorderingTLS13(t *testing.T) { + skipFIPS(t) // No CHACHA20_POLY1305 for FIPS. + currentAESSupport := hasAESGCMHardwareSupport defer func() { hasAESGCMHardwareSupport = currentAESSupport }() diff --git a/handshake_test.go b/handshake_test.go index 41c2643..5a9c24f 100644 --- a/handshake_test.go +++ b/handshake_test.go @@ -50,6 +50,9 @@ var ( ) func runTestAndUpdateIfNeeded(t *testing.T, name string, run func(t *testing.T, update bool), wait bool) { + // FIPS mode is non-deterministic and so isn't suited for testing against static test transcripts. + skipFIPS(t) + success := t.Run(name, func(t *testing.T) { if !*update && !wait { t.Parallel() @@ -523,6 +526,12 @@ var testRSACertificate = fromHex("3082024b308201b4a003020102020900e8f09d3fe25bea var testRSACertificateIssuer = fromHex("3082021930820182a003020102020900ca5e4e811a965964300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100d667b378bb22f34143b6cd2008236abefaf2852adf3ab05e01329e2c14834f5105df3f3073f99dab5442d45ee5f8f57b0111c8cb682fbb719a86944eebfffef3406206d898b8c1b1887797c9c5006547bb8f00e694b7a063f10839f269f2c34fff7a1f4b21fbcd6bfdfb13ac792d1d11f277b5c5b48600992203059f2a8f8cc50203010001a35d305b300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff30190603551d0e041204104813494d137e1631bba301d5acab6e7b300d06092a864886f70d01010b050003818100c1154b4bab5266221f293766ae4138899bd4c5e36b13cee670ceeaa4cbdf4f6679017e2fe649765af545749fe4249418a56bd38a04b81e261f5ce86b8d5c65413156a50d12449554748c59a30c515bc36a59d38bddf51173e899820b282e40aa78c806526fd184fb6b4cf186ec728edffa585440d2b3225325f7ab580e87dd76") +var testRSA2048Certificate = fromHex("30820316308201fea003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3338303130313030303030305a301a310b3009060355040a1302476f310b300906035504031302476f30820122300d06092a864886f70d01010105000382010f003082010a0282010100e0ac47db9ba1b7f98a996c62dc1d248d4ee570544136fe4e911e22fccc0fe2b20982f3c4cdd8f4065c5068c873ca0a768b80dc915edc66541a5f26cdea44e56e411221e2f9927bf4e009fee76dbe0e118dcc13392efd6f42d8eb2fd5bc8f63ac77800c84d3be90c20c321273254b9137ef61f825dad1ec2c5e75aa4be6d3104899bd5ac400da7ab942b4227a3870ae5bb97870aa09a1082fb8e78b944cd7fd1b0c6fb1cce03b5430b12ef9ce2d95e01821766e998df0cc99202a57cf030577bd2dc0ec85a49f203511bb6f0e9f43398ead0958f8d7534c61e81daf4501faaa68d9cbc725b58401900fa48a3e2333b15c88cf0c5cc8f33fb9464f9d5f5768b8f10203010001a35a3058300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b050003820101009e83f835e2da08204ee6f8bdca793cf83c7aec175349c1642dfbe9f4d0dcfb1aedb4d0122e16c2ad92e63dd31cce10ca5dd04be48cded0fdc8fea49e891d9d93e778a67d54b619ac167ce7bb0f6000ca00c5677d09df3eb10080134ba32bfe4132d33954dc479cb266288d53d3f43af9c78c0ca59d396498bdc56d4966dc6b7e49081f7f2ae1d704bb9f9effed93c57d3b738da02edff3999e3f1a5dce2b093951947d233d9c6b6a12b4b1611826aa02544980089eebbcf22a1a96bd35a3ddf638578989334a93d5081fab442b4383ba6213b7cdd74110582244a2abd937828b311d8dd69178756db7874293b9810c5c2e833f91d49d283a62caaf359141997f") + +var testRSA2048CertificateIssuer = fromHex("308203223082020aa003020102020900ca5e4e811a965964300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f7430820122300d06092a864886f70d01010105000382010f003082010a0282010100b308c1720c7054abe66e1be6f8a11246808215a810e8936e47601f7ec1afeb02ad69a5000959d4e08ebc4455ef90b39616f380b8ff2e76f29942d7e009cf010824fe56f69140ac39b761595255ec2aa35155ca2eea884f57b25f8a52f41f56f65b0197cb6c637f9adfa97d8ac27565449f64e67f8b918646ffd630601b0badd8d38aea421fe413ee94f10ea5874c2fd6d8c1b9febaa5ca0ce759993a232c9c48e52230bbf58777b0c30e07e9e0914133730d844b9887b950d5a17c779ac69de2d9c65d26f1ea46c7dd7ac636af6d77df7c9218f78c7b5f08b025867f343ac66cd43a657ac44bfd7e9d07e95a22ff9a0babf72dcffc66eba0a1d90731f67e3bbd0203010001a361305f300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff301d0603551d0e0416041460145a6ce2e8a15b1b68db9a4752ce8684d6ba2d300d06092a864886f70d01010b050003820101001d342fe0b50a25d57a8b13bc14d0abb1eea7431ee752aa423e1306654183e44e9d48bbf592cd32ce77310fdc4e8bbcd724fc43d2723f454bfe605ff90d38d8c6fe60b36c6f4d2d7e4e79bceeb2484f0565274b0d0c4a8562370677624a4c133e332a9e63d4b47544c14e4908ee8685dd0760ae6f4ab089ede2b0cdc595ecefbee7d8be80d57b2d4e4510b6ceda54d1a5980540214191d81cc89a983da43d4043f8efe97a2e231c5153bded520acce87ec8c64a3408f0eb4c742c4a877e8b5b7b7f72497734a41a95994a7a103262ea6d598d03fd5cb0579ed4702424da8893334c58215bc655d49656aedcd02d18676f45d6b9469ae04b89abe9b358391cce99") + +var testRSA2048PrivateKey, _ = x509.ParsePKCS1PrivateKey(fromHex("308204a40201000282010100e0ac47db9ba1b7f98a996c62dc1d248d4ee570544136fe4e911e22fccc0fe2b20982f3c4cdd8f4065c5068c873ca0a768b80dc915edc66541a5f26cdea44e56e411221e2f9927bf4e009fee76dbe0e118dcc13392efd6f42d8eb2fd5bc8f63ac77800c84d3be90c20c321273254b9137ef61f825dad1ec2c5e75aa4be6d3104899bd5ac400da7ab942b4227a3870ae5bb97870aa09a1082fb8e78b944cd7fd1b0c6fb1cce03b5430b12ef9ce2d95e01821766e998df0cc99202a57cf030577bd2dc0ec85a49f203511bb6f0e9f43398ead0958f8d7534c61e81daf4501faaa68d9cbc725b58401900fa48a3e2333b15c88cf0c5cc8f33fb9464f9d5f5768b8f10203010001028201007aac96efca229b199e1bf79a63256677e1c455792bc2a348b2e409a68ea57dda486740430d4290bb885c3f5a741eb567d4f41f7b2098a726f4df4f88cf899edc7c9b31f584dffedece15a7212642c7dbbdd8d806392a183e1fc30af36169c9bab9e528f0bdcd27ad4c8b6a97849da6452c6809de61848db80c3ba3289e785042cdfd46fbfee5f78adcba2927fcd8cbe9dcaa97190457eaa45d77adbe0db820aff0c8511d837ab5b307bad5f85afd2cc70d9659ec58045d97ced1eb7950670ac559449c0305fddefda1bac88d36629a177f65abad182c6470830b39e7f6dbdef4df813ccaef01d5a42d37213b2b9647e2ff56a63e6b6a4b6e8a1567bbfd77042102818100eb66f205e8507c78f7167dbef3ddf02fde6a67bd15152609e9296576e28c79678177145ae98e0a2fee58fdb3d626fb6beae3e0ae0b76bc47d16fcdeb16f0caca8a0902779979382609705ae84514de480c2fb2ddda3049347cc1bde9f1a359747079ef3dce020a3c186c90e63bc20b5489a40d768b1c1c35c679edc5662e18c702818100f454ffff95b126b55cb13b68a3841600fc0bc69ff4064f7ceb122495fa972fdb05ca2fa1c6e2e84432f81c96875ab12226e8ce92ba808c4f6325f27ce058791f05db96e623687d3cfc198e748a07521a8c7ee9e7e8faf95b0985be82b867a49f7d5d50fac3881d2c39dedfdbca3ebe847b859c9864cf7a543e4688f5a60118870281806cee737ac65950704daeebbb8c701c709a54d4f28baa00b33f6137a1bf0e5033d4963d2620c3e8f4eb2fe51eee2f95d3079c31e1784e96ac093fdaa33a376d3032961ebd27990fa192669abab715041385082196461c6813d0d37ac5a25afbcf452937cb7ae438c63c6b28d651bae6b1550c446aa1cefd42e9388d0df6cdc80b02818100cac172c33504923bb494fad8e5c0a9c5dd63244bfe63f238969632b82700a95cd71c2694d887d9f92656d0da75ae640a1441e392cda3f94bb3da7cb4f6335527d2639c809467946e34423cfe26c0d6786398ba20922d1b1a59f79bd5bc937d8040b75c890c13fb298548977a3c05ff71cf535c54f66b5a77684a7e4363a3cb2702818100a4d782f35d5a07f9c1f8f9c378564b220387d1e481cc856b631de7637d8bb77c851db070122050ac230dc6e45edf4523471c717c1cb86a36b2fd3358fae349d51be54d71d7dbeaa6af668323e2b51933f0b8488aa12723e0f32207068b4aa64ed54bcef4acbbbe35b92802faba7ed45ae52bef8313d9ef4393ccc5cf868ddbf8")) + // testRSAPSSCertificate has signatureAlgorithm rsassaPss, but subjectPublicKeyInfo // algorithm rsaEncryption, for use with the rsa_pss_rsae_* SignatureSchemes. // See also TestRSAPSSKeyError. testRSAPSSCertificate is self-signed. diff --git a/tls_test.go b/tls_test.go index 394d517..7dd5ddd 100644 --- a/tls_test.go +++ b/tls_test.go @@ -13,6 +13,7 @@ import ( "crypto/elliptic" "crypto/internal/hpke" "crypto/rand" + "crypto/tls/internal/fips140tls" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" @@ -178,6 +179,40 @@ func newLocalListener(t testing.TB) net.Listener { return ln } +func runWithFIPSEnabled(t *testing.T, testFunc func(t *testing.T)) { + originalFIPS := fips140tls.Required() + defer func() { + if originalFIPS { + fips140tls.Force() + } else { + fips140tls.TestingOnlyAbandon() + } + }() + + fips140tls.Force() + t.Run("fips140tls", testFunc) +} + +func runWithFIPSDisabled(t *testing.T, testFunc func(t *testing.T)) { + originalFIPS := fips140tls.Required() + defer func() { + if originalFIPS { + fips140tls.Force() + } else { + fips140tls.TestingOnlyAbandon() + } + }() + + fips140tls.TestingOnlyAbandon() + t.Run("no-fips140tls", testFunc) +} + +func skipFIPS(t *testing.T) { + if fips140tls.Required() { + t.Skip("skipping test in FIPS mode") + } +} + func TestDialTimeout(t *testing.T) { if testing.Short() { t.Skip("skipping in short mode") @@ -1114,6 +1149,8 @@ func TestConnectionStateMarshal(t *testing.T) { } func TestConnectionState(t *testing.T) { + skipFIPS(t) // Test certificates not FIPS compatible. + issuer, err := x509.ParseCertificate(testRSACertificateIssuer) if err != nil { panic(err) @@ -1254,6 +1291,8 @@ func TestBuildNameToCertificate_doesntModifyCertificates(t *testing.T) { func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } func TestClientHelloInfo_SupportsCertificate(t *testing.T) { + skipFIPS(t) // Test certificates not FIPS compatible. + rsaCert := &Certificate{ Certificate: [][]byte{testRSACertificate}, PrivateKey: testRSAPrivateKey, @@ -1703,6 +1742,8 @@ func TestPKCS1OnlyCert(t *testing.T) { } func TestVerifyCertificates(t *testing.T) { + skipFIPS(t) // Test certificates not FIPS compatible. + // See https://go.dev/issue/31641. t.Run("TLSv12", func(t *testing.T) { testVerifyCertificates(t, VersionTLS12) }) t.Run("TLSv13", func(t *testing.T) { testVerifyCertificates(t, VersionTLS13) }) @@ -1847,6 +1888,8 @@ func testVerifyCertificates(t *testing.T, version uint16) { } func TestHandshakeKyber(t *testing.T) { + skipFIPS(t) // No Kyber768 in FIPS + if x25519Kyber768Draft00.String() != "X25519Kyber768Draft00" { t.Fatalf("unexpected CurveID string: %v", x25519Kyber768Draft00.String()) } From 68e64cfceb57e3460637a1b1633ebe7a7b9d2c3f Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 20 Nov 2024 13:59:09 +0100 Subject: [PATCH 26/34] crypto/rsa: refuse to generate and/or use keys smaller than 1024 bits Fixes #68762 Change-Id: Id89c770571d7cc27c6cf7932139ec3424383a7ef Reviewed-on: https://go-review.googlesource.com/c/go/+/629938 Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI --- fips_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fips_test.go b/fips_test.go index 5447aa1..52266de 100644 --- a/fips_test.go +++ b/fips_test.go @@ -350,7 +350,7 @@ func TestFIPSCertAlgs(t *testing.T) { // Set up some roots, intermediate CAs, and leaf certs with various algorithms. // X_Y is X signed by Y. R1 := fipsCert(t, "R1", fipsRSAKey(t, 2048), nil, fipsCertCA|fipsCertFIPSOK) - R2 := fipsCert(t, "R2", fipsRSAKey(t, 512), nil, fipsCertCA) + R2 := fipsCert(t, "R2", fipsRSAKey(t, 1024), nil, fipsCertCA) R3 := fipsCert(t, "R3", fipsRSAKey(t, 4096), nil, fipsCertCA|fipsCertFIPSOK) M1_R1 := fipsCert(t, "M1_R1", fipsECDSAKey(t, elliptic.P256()), R1, fipsCertCA|fipsCertFIPSOK) From 77ea502eeed61e651736919aeef77bcb10dd4425 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 21 Nov 2024 21:21:58 +0100 Subject: [PATCH 27/34] crypto/tls: implement X25519MLKEM768 This makes three related changes that work particularly well together and would require significant extra work to do separately: it replaces X25519Kyber768Draft00 with X25519MLKEM768, it makes CurvePreferences ordering crypto/tls-selected, and applies a preference to PQ key exchange methods over key shares (to mitigate downgrades). TestHandshakeServerUnsupportedKeyShare was removed because we are not rejecting unsupported key shares anymore (nor do we select them, and rejecting them actively is a MAY). It would have been nice to keep the test to check we still continue successfully, but testClientHelloFailure is broken in the face of any server-side behavior which requires writing any other messages back to the client, or reading them. Updates #69985 Fixes #69393 Change-Id: I58de76f5b8742a9bd4543fd7907c48e038507b19 Reviewed-on: https://go-review.googlesource.com/c/go/+/630775 Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: Go LUCI --- bogo_config.json | 13 ++++-- bogo_shim_test.go | 9 ++-- common.go | 62 ++++++++++++++------------- common_string.go | 6 +-- defaults.go | 9 ++-- fips_test.go | 5 +-- handshake_client.go | 25 ++++++----- handshake_client_tls13.go | 29 ++++++------- handshake_server.go | 2 +- handshake_server_test.go | 16 ------- handshake_server_tls13.go | 89 ++++++++++++++++++++++++--------------- key_schedule.go | 36 +--------------- key_schedule_test.go | 19 --------- tls_test.go | 63 +++++++++++++++------------ 14 files changed, 177 insertions(+), 206 deletions(-) diff --git a/bogo_config.json b/bogo_config.json index cfd9579..1c313ec 100644 --- a/bogo_config.json +++ b/bogo_config.json @@ -33,8 +33,14 @@ "TLS-ECH-Server-EarlyData": "Go does not support early (0-RTT) data", "TLS-ECH-Server-EarlyDataRejected": "Go does not support early (0-RTT) data", - "CurveTest-Client-Kyber-TLS13": "Temporarily disabled since the curve ID is not exposed and it cannot be correctly configured", - "CurveTest-Server-Kyber-TLS13": "Temporarily disabled since the curve ID is not exposed and it cannot be correctly configured", + "MLKEMKeyShareIncludedSecond": "BoGo wants us to order the key shares based on its preference, but we don't support that", + "MLKEMKeyShareIncludedThird": "BoGo wants us to order the key shares based on its preference, but we don't support that", + "PostQuantumNotEnabledByDefaultInClients": "We do enable it by default!", + "*-Kyber-TLS13": "We don't support Kyber, only ML-KEM (BoGo bug ignoring AllCurves?)", + + "SendEmptySessionTicket-TLS13": "https://github.com/golang/go/issues/70513", + + "*-SignDefault-*": "TODO, partially it encodes BoringSSL defaults, partially we might be missing some implicit behavior of a missing flag", "SendV2ClientHello*": "We don't support SSLv2", "*QUIC*": "No QUIC support", @@ -238,6 +244,7 @@ 23, 24, 25, - 29 + 29, + 4588 ] } diff --git a/bogo_shim_test.go b/bogo_shim_test.go index 561f0a6..fdacbee 100644 --- a/bogo_shim_test.go +++ b/bogo_shim_test.go @@ -420,7 +420,7 @@ func TestBogoSuite(t *testing.T) { if *bogoLocalDir != "" { bogoDir = *bogoLocalDir } else { - const boringsslModVer = "v0.0.0-20240523173554-273a920f84e8" + const boringsslModVer = "v0.0.0-20241120195446-5cce3fbd23e1" bogoDir = cryptotest.FetchModule(t, "boringssl.googlesource.com/boringssl.git", boringsslModVer) } @@ -473,11 +473,8 @@ func TestBogoSuite(t *testing.T) { // are present in the output. They are only checked if -bogo-filter // was not passed. assertResults := map[string]string{ - // TODO: these tests are temporarily disabled, since we don't expose the - // necessary curve ID, and it's currently not possible to correctly - // configure it. - // "CurveTest-Client-Kyber-TLS13": "PASS", - // "CurveTest-Server-Kyber-TLS13": "PASS", + "CurveTest-Client-MLKEM-TLS13": "PASS", + "CurveTest-Server-MLKEM-TLS13": "PASS", } for name, result := range results.Tests { diff --git a/common.go b/common.go index 56f2acf..f98d24b 100644 --- a/common.go +++ b/common.go @@ -145,17 +145,21 @@ const ( type CurveID uint16 const ( - CurveP256 CurveID = 23 - CurveP384 CurveID = 24 - CurveP521 CurveID = 25 - X25519 CurveID = 29 - - // Experimental codepoint for X25519Kyber768Draft00, specified in - // draft-tls-westerbaan-xyber768d00-03. Not exported, as support might be - // removed in the future. - x25519Kyber768Draft00 CurveID = 0x6399 // X25519Kyber768Draft00 + CurveP256 CurveID = 23 + CurveP384 CurveID = 24 + CurveP521 CurveID = 25 + X25519 CurveID = 29 + X25519MLKEM768 CurveID = 4588 ) +func isTLS13OnlyKeyExchange(curve CurveID) bool { + return curve == X25519MLKEM768 +} + +func isPQKeyExchange(curve CurveID) bool { + return curve == X25519MLKEM768 +} + // TLS 1.3 Key Share. See RFC 8446, Section 4.2.8. type keyShare struct { group CurveID @@ -419,9 +423,12 @@ type ClientHelloInfo struct { // client is using SNI (see RFC 4366, Section 3.1). ServerName string - // SupportedCurves lists the elliptic curves supported by the client. - // SupportedCurves is set only if the Supported Elliptic Curves - // Extension is being used (see RFC 4492, Section 5.1.1). + // SupportedCurves lists the key exchange mechanisms supported by the + // client. It was renamed to "supported groups" in TLS 1.3, see RFC 8446, + // Section 4.2.7 and [CurveID]. + // + // SupportedCurves may be nil in TLS 1.2 and lower if the Supported Elliptic + // Curves Extension is not being used (see RFC 4492, Section 5.1.1). SupportedCurves []CurveID // SupportedPoints lists the point formats supported by the client. @@ -761,14 +768,15 @@ type Config struct { // which is currently TLS 1.3. MaxVersion uint16 - // CurvePreferences contains the elliptic curves that will be used in - // an ECDHE handshake, in preference order. If empty, the default will - // be used. The client will use the first preference as the type for - // its key share in TLS 1.3. This may change in the future. + // CurvePreferences contains a set of supported key exchange mechanisms. + // The name refers to elliptic curves for legacy reasons, see [CurveID]. + // The order of the list is ignored, and key exchange mechanisms are chosen + // from this list using an internal preference order. If empty, the default + // will be used. // - // From Go 1.23, the default includes the X25519Kyber768Draft00 hybrid + // From Go 1.24, the default includes the [X25519MLKEM768] hybrid // post-quantum key exchange. To disable it, set CurvePreferences explicitly - // or use the GODEBUG=tlskyber=0 environment variable. + // or use the GODEBUG=tlsmlkem=0 environment variable. CurvePreferences []CurveID // DynamicRecordSizingDisabled disables adaptive sizing of TLS records. @@ -1176,23 +1184,19 @@ func supportedVersionsFromMax(maxVersion uint16) []uint16 { func (c *Config) curvePreferences(version uint16) []CurveID { var curvePreferences []CurveID - if c != nil && len(c.CurvePreferences) != 0 { - curvePreferences = slices.Clone(c.CurvePreferences) - if fips140tls.Required() { - return slices.DeleteFunc(curvePreferences, func(c CurveID) bool { - return !slices.Contains(defaultCurvePreferencesFIPS, c) - }) - } - } else if fips140tls.Required() { + if fips140tls.Required() { curvePreferences = slices.Clone(defaultCurvePreferencesFIPS) } else { curvePreferences = defaultCurvePreferences() } - if version < VersionTLS13 { - return slices.DeleteFunc(curvePreferences, func(c CurveID) bool { - return c == x25519Kyber768Draft00 + if c != nil && len(c.CurvePreferences) != 0 { + curvePreferences = slices.DeleteFunc(curvePreferences, func(x CurveID) bool { + return !slices.Contains(c.CurvePreferences, x) }) } + if version < VersionTLS13 { + curvePreferences = slices.DeleteFunc(curvePreferences, isTLS13OnlyKeyExchange) + } return curvePreferences } diff --git a/common_string.go b/common_string.go index 1752f81..e15dd48 100644 --- a/common_string.go +++ b/common_string.go @@ -71,13 +71,13 @@ func _() { _ = x[CurveP384-24] _ = x[CurveP521-25] _ = x[X25519-29] - _ = x[x25519Kyber768Draft00-25497] + _ = x[X25519MLKEM768-4588] } const ( _CurveID_name_0 = "CurveP256CurveP384CurveP521" _CurveID_name_1 = "X25519" - _CurveID_name_2 = "X25519Kyber768Draft00" + _CurveID_name_2 = "X25519MLKEM768" ) var ( @@ -91,7 +91,7 @@ func (i CurveID) String() string { return _CurveID_name_0[_CurveID_index_0[i]:_CurveID_index_0[i+1]] case i == 29: return _CurveID_name_1 - case i == 25497: + case i == 4588: return _CurveID_name_2 default: return "CurveID(" + strconv.FormatInt(int64(i), 10) + ")" diff --git a/defaults.go b/defaults.go index 170c200..f25d0d3 100644 --- a/defaults.go +++ b/defaults.go @@ -13,14 +13,15 @@ import ( // Defaults are collected in this file to allow distributions to more easily patch // them to apply local policies. -var tlskyber = godebug.New("tlskyber") +var tlsmlkem = godebug.New("tlsmlkem") +// defaultCurvePreferences is the default set of supported key exchanges, as +// well as the preference order. func defaultCurvePreferences() []CurveID { - if tlskyber.Value() == "0" { + if tlsmlkem.Value() == "0" { return []CurveID{X25519, CurveP256, CurveP384, CurveP521} } - // For now, x25519Kyber768Draft00 must always be followed by X25519. - return []CurveID{x25519Kyber768Draft00, X25519, CurveP256, CurveP384, CurveP521} + return []CurveID{X25519MLKEM768, X25519, CurveP256, CurveP384, CurveP521} } // defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that diff --git a/fips_test.go b/fips_test.go index 52266de..e891fcc 100644 --- a/fips_test.go +++ b/fips_test.go @@ -184,16 +184,13 @@ func TestFIPSServerCipherSuites(t *testing.T) { func TestFIPSServerCurves(t *testing.T) { serverConfig := testConfig.Clone() + serverConfig.CurvePreferences = nil serverConfig.BuildNameToCertificate() for _, curveid := range defaultCurvePreferences() { t.Run(fmt.Sprintf("curve=%d", curveid), func(t *testing.T) { clientConfig := testConfig.Clone() clientConfig.CurvePreferences = []CurveID{curveid} - if curveid == x25519Kyber768Draft00 { - // x25519Kyber768Draft00 is not supported standalone. - clientConfig.CurvePreferences = append(clientConfig.CurvePreferences, X25519) - } runWithFIPSDisabled(t, func(t *testing.T) { if _, _, err := testHandshake(t, clientConfig, serverConfig); err != nil { diff --git a/handshake_client.go b/handshake_client.go index 548b5f0..ecc62ff 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -24,6 +24,7 @@ import ( "internal/godebug" "io" "net" + "slices" "strconv" "strings" "time" @@ -156,7 +157,9 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCli } curveID := hello.supportedCurves[0] keyShareKeys = &keySharePrivateKeys{curveID: curveID} - if curveID == x25519Kyber768Draft00 { + // Note that if X25519MLKEM768 is supported, it will be first because + // the preference order is fixed. + if curveID == X25519MLKEM768 { keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), X25519) if err != nil { return nil, nil, nil, err @@ -165,18 +168,20 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCli if _, err := io.ReadFull(config.rand(), seed); err != nil { return nil, nil, nil, err } - keyShareKeys.kyber, err = mlkem.NewDecapsulationKey768(seed) + keyShareKeys.mlkem, err = mlkem.NewDecapsulationKey768(seed) if err != nil { return nil, nil, nil, err } - // For draft-tls-westerbaan-xyber768d00-03, we send both a hybrid - // and a standard X25519 key share, since most servers will only - // support the latter. We reuse the same X25519 ephemeral key for - // both, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2. + mlkemEncapsulationKey := keyShareKeys.mlkem.EncapsulationKey().Bytes() + x25519EphemeralKey := keyShareKeys.ecdhe.PublicKey().Bytes() hello.keyShares = []keyShare{ - {group: x25519Kyber768Draft00, data: append(keyShareKeys.ecdhe.PublicKey().Bytes(), - keyShareKeys.kyber.EncapsulationKey().Bytes()...)}, - {group: X25519, data: keyShareKeys.ecdhe.PublicKey().Bytes()}, + {group: X25519MLKEM768, data: append(mlkemEncapsulationKey, x25519EphemeralKey...)}, + } + // If both X25519MLKEM768 and X25519 are supported, we send both key + // shares (as a fallback) and we reuse the same X25519 ephemeral + // key, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2. + if slices.Contains(hello.supportedCurves, X25519) { + hello.keyShares = append(hello.keyShares, keyShare{group: X25519, data: x25519EphemeralKey}) } } else { if _, ok := curveForCurveID(curveID); !ok { @@ -711,7 +716,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { if ok { err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx) if err != nil { - c.sendAlert(alertUnexpectedMessage) + c.sendAlert(alertIllegalParameter) return err } if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ { diff --git a/handshake_client_tls13.go b/handshake_client_tls13.go index 3f4cadb..38c6025 100644 --- a/handshake_client_tls13.go +++ b/handshake_client_tls13.go @@ -322,12 +322,11 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { c.sendAlert(alertIllegalParameter) return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share") } - // Note: we don't support selecting X25519Kyber768Draft00 in a HRR, - // because we currently only support it at all when CurvePreferences is - // empty, which will cause us to also send a key share for it. + // Note: we don't support selecting X25519MLKEM768 in a HRR, because it + // is currently first in preference order, so if it's enabled we'll + // always send a key share for it. // - // This will have to change once we support selecting hybrid KEMs - // without sending key shares for them. + // This will have to change once we support multiple hybrid KEMs. if _, ok := curveForCurveID(curveID); !ok { c.sendAlert(alertInternalError) return errors.New("tls: CurvePreferences includes unsupported curve") @@ -480,12 +479,12 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { c := hs.c ecdhePeerData := hs.serverHello.serverShare.data - if hs.serverHello.serverShare.group == x25519Kyber768Draft00 { - if len(ecdhePeerData) != x25519PublicKeySize+mlkem.CiphertextSize768 { + if hs.serverHello.serverShare.group == X25519MLKEM768 { + if len(ecdhePeerData) != mlkem.CiphertextSize768+x25519PublicKeySize { c.sendAlert(alertIllegalParameter) - return errors.New("tls: invalid server key share") + return errors.New("tls: invalid server X25519MLKEM768 key share") } - ecdhePeerData = hs.serverHello.serverShare.data[:x25519PublicKeySize] + ecdhePeerData = hs.serverHello.serverShare.data[mlkem.CiphertextSize768:] } peerKey, err := hs.keyShareKeys.ecdhe.Curve().NewPublicKey(ecdhePeerData) if err != nil { @@ -497,17 +496,17 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid server key share") } - if hs.serverHello.serverShare.group == x25519Kyber768Draft00 { - if hs.keyShareKeys.kyber == nil { + if hs.serverHello.serverShare.group == X25519MLKEM768 { + if hs.keyShareKeys.mlkem == nil { return c.sendAlert(alertInternalError) } - ciphertext := hs.serverHello.serverShare.data[x25519PublicKeySize:] - kyberShared, err := kyberDecapsulate(hs.keyShareKeys.kyber, ciphertext) + ciphertext := hs.serverHello.serverShare.data[:mlkem.CiphertextSize768] + mlkemShared, err := hs.keyShareKeys.mlkem.Decapsulate(ciphertext) if err != nil { c.sendAlert(alertIllegalParameter) - return errors.New("tls: invalid Kyber server key share") + return errors.New("tls: invalid X25519MLKEM768 server key share") } - sharedKey = append(sharedKey, kyberShared...) + sharedKey = append(mlkemShared, sharedKey...) } c.curveID = hs.serverHello.serverShare.group diff --git a/handshake_server.go b/handshake_server.go index 6fe9628..7c75977 100644 --- a/handshake_server.go +++ b/handshake_server.go @@ -705,7 +705,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers) if err != nil { - c.sendAlert(alertHandshakeFailure) + c.sendAlert(alertIllegalParameter) return err } if hs.hello.extendedMasterSecret { diff --git a/handshake_server_test.go b/handshake_server_test.go index 17453eb..29a802d 100644 --- a/handshake_server_test.go +++ b/handshake_server_test.go @@ -939,22 +939,6 @@ func TestHandshakeServerKeySharePreference(t *testing.T) { runServerTestTLS13(t, test) } -// TestHandshakeServerUnsupportedKeyShare tests a client that sends a key share -// that's not in the supported groups list. -func TestHandshakeServerUnsupportedKeyShare(t *testing.T) { - pk, _ := ecdh.P384().GenerateKey(rand.Reader) - clientHello := &clientHelloMsg{ - vers: VersionTLS12, - random: make([]byte, 32), - supportedVersions: []uint16{VersionTLS13}, - cipherSuites: []uint16{TLS_AES_128_GCM_SHA256}, - compressionMethods: []uint8{compressionNone}, - keyShares: []keyShare{{group: CurveP384, data: pk.PublicKey().Bytes()}}, - supportedCurves: []CurveID{CurveP256}, - } - testClientHelloFailure(t, testConfig, clientHello, "client sent key share for group it does not support") -} - func TestHandshakeServerALPN(t *testing.T) { config := testConfig.Clone() config.NextProtos = []string{"proto1", "proto2"} diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index 76521d8..3552d89 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -20,6 +20,7 @@ import ( "internal/byteorder" "io" "slices" + "sort" "time" ) @@ -195,37 +196,45 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { hs.hello.cipherSuite = hs.suite.id hs.transcript = hs.suite.hash.New() - // Pick the key exchange method in server preference order, but give - // priority to key shares, to avoid a HelloRetryRequest round-trip. - var selectedGroup CurveID - var clientKeyShare *keyShare + // First, if a post-quantum key exchange is available, use one. See + // draft-ietf-tls-key-share-prediction-01, Section 4 for why this must be + // first. + // + // Second, if the client sent a key share for a group we support, use that, + // to avoid a HelloRetryRequest round-trip. + // + // Finally, pick in our fixed preference order. preferredGroups := c.config.curvePreferences(c.vers) - for _, preferredGroup := range preferredGroups { - ki := slices.IndexFunc(hs.clientHello.keyShares, func(ks keyShare) bool { - return ks.group == preferredGroup - }) - if ki != -1 { - clientKeyShare = &hs.clientHello.keyShares[ki] - selectedGroup = clientKeyShare.group - if !slices.Contains(hs.clientHello.supportedCurves, selectedGroup) { - c.sendAlert(alertIllegalParameter) - return errors.New("tls: client sent key share for group it does not support") + preferredGroups = slices.DeleteFunc(preferredGroups, func(group CurveID) bool { + return !slices.Contains(hs.clientHello.supportedCurves, group) + }) + if len(preferredGroups) == 0 { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: no key exchanges supported by both client and server") + } + hasKeyShare := func(group CurveID) bool { + for _, ks := range hs.clientHello.keyShares { + if ks.group == group { + return true } + } + return false + } + sort.SliceStable(preferredGroups, func(i, j int) bool { + return hasKeyShare(preferredGroups[i]) && !hasKeyShare(preferredGroups[j]) + }) + sort.SliceStable(preferredGroups, func(i, j int) bool { + return isPQKeyExchange(preferredGroups[i]) && !isPQKeyExchange(preferredGroups[j]) + }) + selectedGroup := preferredGroups[0] + + var clientKeyShare *keyShare + for _, ks := range hs.clientHello.keyShares { + if ks.group == selectedGroup { + clientKeyShare = &ks break } } - if selectedGroup == 0 { - for _, preferredGroup := range preferredGroups { - if slices.Contains(hs.clientHello.supportedCurves, preferredGroup) { - selectedGroup = preferredGroup - break - } - } - } - if selectedGroup == 0 { - c.sendAlert(alertHandshakeFailure) - return errors.New("tls: no ECDHE curve supported by both client and server") - } if clientKeyShare == nil { ks, err := hs.doHelloRetryRequest(selectedGroup) if err != nil { @@ -237,13 +246,13 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { ecdhGroup := selectedGroup ecdhData := clientKeyShare.data - if selectedGroup == x25519Kyber768Draft00 { + if selectedGroup == X25519MLKEM768 { ecdhGroup = X25519 - if len(ecdhData) != x25519PublicKeySize+mlkem.EncapsulationKeySize768 { + if len(ecdhData) != mlkem.EncapsulationKeySize768+x25519PublicKeySize { c.sendAlert(alertIllegalParameter) - return errors.New("tls: invalid Kyber client key share") + return errors.New("tls: invalid X25519MLKEM768 client key share") } - ecdhData = ecdhData[:x25519PublicKeySize] + ecdhData = ecdhData[mlkem.EncapsulationKeySize768:] } if _, ok := curveForCurveID(ecdhGroup); !ok { c.sendAlert(alertInternalError) @@ -265,14 +274,24 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid client key share") } - if selectedGroup == x25519Kyber768Draft00 { - ciphertext, kyberShared, err := kyberEncapsulate(clientKeyShare.data[x25519PublicKeySize:]) + if selectedGroup == X25519MLKEM768 { + k, err := mlkem.NewEncapsulationKey768(clientKeyShare.data[:mlkem.EncapsulationKeySize768]) if err != nil { c.sendAlert(alertIllegalParameter) - return errors.New("tls: invalid Kyber client key share") + return errors.New("tls: invalid X25519MLKEM768 client key share") } - hs.sharedKey = append(hs.sharedKey, kyberShared...) - hs.hello.serverShare.data = append(hs.hello.serverShare.data, ciphertext...) + ciphertext, mlkemSharedSecret := k.Encapsulate() + // draft-kwiatkowski-tls-ecdhe-mlkem-02, Section 3.1.3: "For + // X25519MLKEM768, the shared secret is the concatenation of the ML-KEM + // shared secret and the X25519 shared secret. The shared secret is 64 + // bytes (32 bytes for each part)." + hs.sharedKey = append(mlkemSharedSecret, hs.sharedKey...) + // draft-kwiatkowski-tls-ecdhe-mlkem-02, Section 3.1.2: "When the + // X25519MLKEM768 group is negotiated, the server's key exchange value + // is the concatenation of an ML-KEM ciphertext returned from + // encapsulation to the client's encapsulation key, and the server's + // ephemeral X25519 share." + hs.hello.serverShare.data = append(ciphertext, hs.hello.serverShare.data...) } selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, c.quic != nil) diff --git a/key_schedule.go b/key_schedule.go index 60527b0..38d6d3f 100644 --- a/key_schedule.go +++ b/key_schedule.go @@ -8,7 +8,6 @@ import ( "crypto/ecdh" "crypto/hmac" "crypto/internal/fips140/mlkem" - "crypto/internal/fips140/sha3" "crypto/internal/fips140/tls13" "errors" "hash" @@ -53,40 +52,7 @@ func (c *cipherSuiteTLS13) exportKeyingMaterial(s *tls13.MasterSecret, transcrip type keySharePrivateKeys struct { curveID CurveID ecdhe *ecdh.PrivateKey - kyber *mlkem.DecapsulationKey768 -} - -// kyberDecapsulate implements decapsulation according to Kyber Round 3. -func kyberDecapsulate(dk *mlkem.DecapsulationKey768, c []byte) ([]byte, error) { - K, err := dk.Decapsulate(c) - if err != nil { - return nil, err - } - return kyberSharedSecret(c, K), nil -} - -// kyberEncapsulate implements encapsulation according to Kyber Round 3. -func kyberEncapsulate(ek []byte) (c, ss []byte, err error) { - k, err := mlkem.NewEncapsulationKey768(ek) - if err != nil { - return nil, nil, err - } - c, ss = k.Encapsulate() - return c, kyberSharedSecret(c, ss), nil -} - -func kyberSharedSecret(c, K []byte) []byte { - // Package mlkem implements ML-KEM, which compared to Kyber removed a - // final hashing step. Compute SHAKE-256(K || SHA3-256(c), 32) to match Kyber. - // See https://words.filippo.io/mlkem768/#bonus-track-using-a-ml-kem-implementation-as-kyber-v3. - h := sha3.NewShake256() - h.Write(K) - ch := sha3.New256() - ch.Write(c) - h.Write(ch.Sum(nil)) - out := make([]byte, 32) - h.Read(out) - return out + mlkem *mlkem.DecapsulationKey768 } const x25519PublicKeySize = 32 diff --git a/key_schedule_test.go b/key_schedule_test.go index f96b14c..1710994 100644 --- a/key_schedule_test.go +++ b/key_schedule_test.go @@ -6,7 +6,6 @@ package tls import ( "bytes" - "crypto/internal/fips140/mlkem" "crypto/internal/fips140/tls13" "crypto/sha256" "encoding/hex" @@ -118,21 +117,3 @@ func TestTrafficKey(t *testing.T) { t.Errorf("cipherSuiteTLS13.trafficKey() gotIV = % x, want % x", gotIV, wantIV) } } - -func TestKyberEncapsulate(t *testing.T) { - dk, err := mlkem.GenerateKey768() - if err != nil { - t.Fatal(err) - } - ct, ss, err := kyberEncapsulate(dk.EncapsulationKey().Bytes()) - if err != nil { - t.Fatal(err) - } - dkSS, err := kyberDecapsulate(dk, ct) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(ss, dkSS) { - t.Fatalf("got %x, want %x", ss, dkSS) - } -} diff --git a/tls_test.go b/tls_test.go index 7dd5ddd..51cd2b9 100644 --- a/tls_test.go +++ b/tls_test.go @@ -1887,26 +1887,21 @@ func testVerifyCertificates(t *testing.T, version uint16) { } } -func TestHandshakeKyber(t *testing.T) { - skipFIPS(t) // No Kyber768 in FIPS - - if x25519Kyber768Draft00.String() != "X25519Kyber768Draft00" { - t.Fatalf("unexpected CurveID string: %v", x25519Kyber768Draft00.String()) - } - +func TestHandshakeMLKEM(t *testing.T) { + skipFIPS(t) // No X25519MLKEM768 in FIPS var tests = []struct { name string clientConfig func(*Config) serverConfig func(*Config) preparation func(*testing.T) expectClientSupport bool - expectKyber bool + expectMLKEM bool expectHRR bool }{ { name: "Default", expectClientSupport: true, - expectKyber: true, + expectMLKEM: true, expectHRR: false, }, { @@ -1922,7 +1917,7 @@ func TestHandshakeKyber(t *testing.T) { config.CurvePreferences = []CurveID{X25519} }, expectClientSupport: true, - expectKyber: false, + expectMLKEM: false, expectHRR: false, }, { @@ -1931,9 +1926,25 @@ func TestHandshakeKyber(t *testing.T) { config.CurvePreferences = []CurveID{CurveP256} }, expectClientSupport: true, - expectKyber: false, + expectMLKEM: false, expectHRR: true, }, + { + name: "ClientMLKEMOnly", + clientConfig: func(config *Config) { + config.CurvePreferences = []CurveID{X25519MLKEM768} + }, + expectClientSupport: true, + expectMLKEM: true, + }, + { + name: "ClientSortedCurvePreferences", + clientConfig: func(config *Config) { + config.CurvePreferences = []CurveID{CurveP256, X25519MLKEM768} + }, + expectClientSupport: true, + expectMLKEM: true, + }, { name: "ClientTLSv12", clientConfig: func(config *Config) { @@ -1947,12 +1958,12 @@ func TestHandshakeKyber(t *testing.T) { config.MaxVersion = VersionTLS12 }, expectClientSupport: true, - expectKyber: false, + expectMLKEM: false, }, { name: "GODEBUG", preparation: func(t *testing.T) { - t.Setenv("GODEBUG", "tlskyber=0") + t.Setenv("GODEBUG", "tlsmlkem=0") }, expectClientSupport: false, }, @@ -1972,10 +1983,10 @@ func TestHandshakeKyber(t *testing.T) { test.serverConfig(serverConfig) } serverConfig.GetConfigForClient = func(hello *ClientHelloInfo) (*Config, error) { - if !test.expectClientSupport && slices.Contains(hello.SupportedCurves, x25519Kyber768Draft00) { - return nil, errors.New("client supports Kyber768Draft00") - } else if test.expectClientSupport && !slices.Contains(hello.SupportedCurves, x25519Kyber768Draft00) { - return nil, errors.New("client does not support Kyber768Draft00") + if !test.expectClientSupport && slices.Contains(hello.SupportedCurves, X25519MLKEM768) { + return nil, errors.New("client supports X25519MLKEM768") + } else if test.expectClientSupport && !slices.Contains(hello.SupportedCurves, X25519MLKEM768) { + return nil, errors.New("client does not support X25519MLKEM768") } return nil, nil } @@ -1987,19 +1998,19 @@ func TestHandshakeKyber(t *testing.T) { if err != nil { t.Fatal(err) } - if test.expectKyber { - if ss.testingOnlyCurveID != x25519Kyber768Draft00 { - t.Errorf("got CurveID %v (server), expected %v", ss.testingOnlyCurveID, x25519Kyber768Draft00) + if test.expectMLKEM { + if ss.testingOnlyCurveID != X25519MLKEM768 { + t.Errorf("got CurveID %v (server), expected %v", ss.testingOnlyCurveID, X25519MLKEM768) } - if cs.testingOnlyCurveID != x25519Kyber768Draft00 { - t.Errorf("got CurveID %v (client), expected %v", cs.testingOnlyCurveID, x25519Kyber768Draft00) + if cs.testingOnlyCurveID != X25519MLKEM768 { + t.Errorf("got CurveID %v (client), expected %v", cs.testingOnlyCurveID, X25519MLKEM768) } } else { - if ss.testingOnlyCurveID == x25519Kyber768Draft00 { - t.Errorf("got CurveID %v (server), expected not Kyber", ss.testingOnlyCurveID) + if ss.testingOnlyCurveID == X25519MLKEM768 { + t.Errorf("got CurveID %v (server), expected not X25519MLKEM768", ss.testingOnlyCurveID) } - if cs.testingOnlyCurveID == x25519Kyber768Draft00 { - t.Errorf("got CurveID %v (client), expected not Kyber", cs.testingOnlyCurveID) + if cs.testingOnlyCurveID == X25519MLKEM768 { + t.Errorf("got CurveID %v (client), expected not X25519MLKEM768", cs.testingOnlyCurveID) } } if test.expectHRR { From edca40051a9af7b097556666d4d7235c5b48a2dd Mon Sep 17 00:00:00 2001 From: Hiroaki Sano Date: Tue, 26 Nov 2024 16:43:04 +0900 Subject: [PATCH 28/34] crypto/tls: fix a broken link Change-Id: I5d4baa454487a810f138334b613b412a5273311e Reviewed-on: https://go-review.googlesource.com/c/go/+/631875 Reviewed-by: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda Reviewed-by: Russ Cox --- cipher_suites.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cipher_suites.go b/cipher_suites.go index 9e831a9..01d6568 100644 --- a/cipher_suites.go +++ b/cipher_suites.go @@ -235,7 +235,7 @@ var cipherSuitesTLS13 = []*cipherSuiteTLS13{ // TODO: replace with a map. // - Anything else comes before CBC_SHA256 // // SHA-256 variants of the CBC ciphersuites don't implement any Lucky13 -// countermeasures. See http://www.isg.rhul.ac.uk/tls/Lucky13.html and +// countermeasures. See https://www.isg.rhul.ac.uk/tls/Lucky13.html and // https://www.imperialviolet.org/2013/02/04/luckythirteen.html. // // - Anything else comes before 3DES From 355add664f2121dcc4e5d26f27aeefee793a1fee Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Tue, 17 Dec 2024 20:47:17 +0100 Subject: [PATCH 29/34] crypto/tls: normalize spelling of "ClientHello" in comments Change-Id: I2b62fb37ae390c42682354eaa2a9d03159563b6d Reviewed-on: https://go-review.googlesource.com/c/go/+/637179 Reviewed-by: Daniel McCarney Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: David Chase --- common.go | 4 ++-- handshake_client.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common.go b/common.go index f98d24b..d6942d2 100644 --- a/common.go +++ b/common.go @@ -456,7 +456,7 @@ type ClientHelloInfo struct { SupportedVersions []uint16 // Extensions lists the IDs of the extensions presented by the client - // in the client hello. + // in the ClientHello. Extensions []uint16 // Conn is the underlying net.Conn for the connection. Do not read @@ -821,7 +821,7 @@ type Config struct { // EncryptedClientHelloRejectionVerify, if not nil, is called when ECH is // rejected by the remote server, in order to verify the ECH provider - // certificate in the outer Client Hello. If it returns a non-nil error, the + // certificate in the outer ClientHello. If it returns a non-nil error, the // handshake is aborted and that error results. // // On the server side this field is not used. diff --git a/handshake_client.go b/handshake_client.go index ecc62ff..3bf703e 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -944,7 +944,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { } // checkALPN ensure that the server's choice of ALPN protocol is compatible with -// the protocols that we advertised in the Client Hello. +// the protocols that we advertised in the ClientHello. func checkALPN(clientProtos []string, serverProto string, quic bool) error { if serverProto == "" { if quic && len(clientProtos) > 0 { From c75d0ae38e1829368b0482e4f0b4eeba47f9fbf3 Mon Sep 17 00:00:00 2001 From: Alec Bakholdin Date: Sun, 22 Dec 2024 20:36:59 -0500 Subject: [PATCH 30/34] crypto/mlkem: swap order of return values of Encapsulate Per FIPS 203 (https://csrc.nist.gov/pubs/fips/203/final), the order of return values should be sharedKey, ciphertext. This commit simply swaps those return values and updates any consumers of the Encapsulate() method to respect the new order. Fixes #70950 Change-Id: I2a0d605e3baf7fe69510d60d3d35bbac18f883c9 Reviewed-on: https://go-review.googlesource.com/c/go/+/638376 LUCI-TryBot-Result: Go LUCI Reviewed-by: Austin Clements Auto-Submit: Ian Lance Taylor Reviewed-by: Filippo Valsorda Reviewed-by: Cherry Mui --- handshake_server_tls13.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handshake_server_tls13.go b/handshake_server_tls13.go index 3552d89..76fff69 100644 --- a/handshake_server_tls13.go +++ b/handshake_server_tls13.go @@ -280,7 +280,7 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid X25519MLKEM768 client key share") } - ciphertext, mlkemSharedSecret := k.Encapsulate() + mlkemSharedSecret, ciphertext := k.Encapsulate() // draft-kwiatkowski-tls-ecdhe-mlkem-02, Section 3.1.3: "For // X25519MLKEM768, the shared secret is the concatenation of the ML-KEM // shared secret and the X25519 shared secret. The shared secret is 64 From 31335b3f8f7d167e35f688ebbb6f917f0d926d69 Mon Sep 17 00:00:00 2001 From: thekuwayama Date: Mon, 30 Dec 2024 20:00:49 +0000 Subject: [PATCH 31/34] crypto/tls: fix misspelling in comment Change-Id: Ie36a19ed6d6922e68f98e43745a417a24f8a7828 GitHub-Last-Rev: 6fb32e3d1d4f35704d466b53796e8ddeaf936d72 GitHub-Pull-Request: golang/go#71060 Reviewed-on: https://go-review.googlesource.com/c/go/+/639215 Auto-Submit: Ian Lance Taylor Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- handshake_messages.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handshake_messages.go b/handshake_messages.go index fa00d7b..6c6141c 100644 --- a/handshake_messages.go +++ b/handshake_messages.go @@ -97,7 +97,7 @@ type clientHelloMsg struct { pskBinders [][]byte quicTransportParameters []byte encryptedClientHello []byte - // extensions are only populated on the servers-ide of a handshake + // extensions are only populated on the server-side of a handshake extensions []uint16 } From a43aca286c1e175d23a485186dd0d59d14a6f9ec Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 2 Jan 2025 01:34:40 +0100 Subject: [PATCH 32/34] crypto/tls: fix Config.Time in tests using expired certificates Fixes #71077 Change-Id: I6a6a465685f3bd50a5bb35a160f87b59b74fa6af Reviewed-on: https://go-review.googlesource.com/c/go/+/639655 Auto-Submit: Ian Lance Taylor Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Auto-Submit: Damien Neil Reviewed-by: Joel Sing Reviewed-by: Ian Lance Taylor --- handshake_client_test.go | 30 ++++++++++++++++++------------ handshake_server_test.go | 2 ++ handshake_test.go | 5 +++++ tls_test.go | 6 ++---- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/handshake_client_test.go b/handshake_client_test.go index bb164bb..bc54475 100644 --- a/handshake_client_test.go +++ b/handshake_client_test.go @@ -856,6 +856,7 @@ func testResumption(t *testing.T, version uint16) { MaxVersion: version, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, Certificates: testCertificates, + Time: testTime, } issuer, err := x509.ParseCertificate(testRSA2048CertificateIssuer) @@ -872,6 +873,7 @@ func testResumption(t *testing.T, version uint16) { ClientSessionCache: NewLRUClientSessionCache(32), RootCAs: rootCAs, ServerName: "example.golang", + Time: testTime, } testResumeState := func(test string, didResume bool) { @@ -918,7 +920,7 @@ func testResumption(t *testing.T, version uint16) { // An old session ticket is replaced with a ticket encrypted with a fresh key. ticket = getTicket() - serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) } + serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) } testResumeState("ResumeWithOldTicket", true) if bytes.Equal(ticket, getTicket()) { t.Fatal("old first ticket matches the fresh one") @@ -926,13 +928,13 @@ func testResumption(t *testing.T, version uint16) { // Once the session master secret is expired, a full handshake should occur. ticket = getTicket() - serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) } + serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + time.Minute) } testResumeState("ResumeWithExpiredTicket", false) if bytes.Equal(ticket, getTicket()) { t.Fatal("expired first ticket matches the fresh one") } - serverConfig.Time = func() time.Time { return time.Now() } // reset the time back + serverConfig.Time = testTime // reset the time back key1 := randomKey() serverConfig.SetSessionTicketKeys([][32]byte{key1}) @@ -949,11 +951,11 @@ func testResumption(t *testing.T, version uint16) { testResumeState("KeyChangeFinish", true) // Age the session ticket a bit, but not yet expired. - serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) } + serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) } testResumeState("OldSessionTicket", true) ticket = getTicket() // Expire the session ticket, which would force a full handshake. - serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) } + serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + 2*time.Minute) } testResumeState("ExpiredSessionTicket", false) if bytes.Equal(ticket, getTicket()) { t.Fatal("new ticket wasn't provided after old ticket expired") @@ -961,7 +963,7 @@ func testResumption(t *testing.T, version uint16) { // Age the session ticket a bit at a time, but don't expire it. d := 0 * time.Hour - serverConfig.Time = func() time.Time { return time.Now().Add(d) } + serverConfig.Time = func() time.Time { return testTime().Add(d) } deleteTicket() testResumeState("GetFreshSessionTicket", false) for i := 0; i < 13; i++ { @@ -972,7 +974,7 @@ func testResumption(t *testing.T, version uint16) { // handshake occurs for TLS 1.2. Resumption should still occur for // TLS 1.3 since the client should be using a fresh ticket sent over // by the server. - d += 12 * time.Hour + d += 12*time.Hour + time.Minute if version == VersionTLS13 { testResumeState("ExpiredSessionTicket", true) } else { @@ -988,6 +990,7 @@ func testResumption(t *testing.T, version uint16) { MaxVersion: version, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, Certificates: testCertificates, + Time: testTime, } serverConfig.SetSessionTicketKeys([][32]byte{key2}) @@ -1013,6 +1016,7 @@ func testResumption(t *testing.T, version uint16) { CurvePreferences: []CurveID{CurveP521, CurveP384, CurveP256}, MaxVersion: version, Certificates: testCertificates, + Time: testTime, } testResumeState("InitialHandshake", false) testResumeState("WithHelloRetryRequest", true) @@ -1022,6 +1026,7 @@ func testResumption(t *testing.T, version uint16) { MaxVersion: version, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, Certificates: testCertificates, + Time: testTime, } } @@ -1743,6 +1748,7 @@ func testVerifyConnection(t *testing.T, version uint16) { serverConfig := &Config{ MaxVersion: version, Certificates: testCertificates, + Time: testTime, ClientCAs: rootCAs, NextProtos: []string{"protocol1"}, } @@ -1756,6 +1762,7 @@ func testVerifyConnection(t *testing.T, version uint16) { RootCAs: rootCAs, ServerName: "example.golang", Certificates: testCertificates, + Time: testTime, NextProtos: []string{"protocol1"}, } test.configureClient(clientConfig, &clientCalled) @@ -1799,8 +1806,6 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) { rootCAs := x509.NewCertPool() rootCAs.AddCert(issuer) - now := func() time.Time { return time.Unix(1476984729, 0) } - sentinelErr := errors.New("TestVerifyPeerCertificate") verifyPeerCertificateCallback := func(called *bool, rawCerts [][]byte, validatedChains [][]*x509.Certificate) error { @@ -2046,7 +2051,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) { config.ServerName = "example.golang" config.ClientAuth = RequireAndVerifyClientCert config.ClientCAs = rootCAs - config.Time = now + config.Time = testTime config.MaxVersion = version config.Certificates = make([]Certificate, 1) config.Certificates[0].Certificate = [][]byte{testRSA2048Certificate} @@ -2064,7 +2069,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) { config.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}} config.ServerName = "example.golang" config.RootCAs = rootCAs - config.Time = now + config.Time = testTime config.MaxVersion = version test.configureClient(config, &clientCalled) clientErr := Client(c, config).Handshake() @@ -2379,7 +2384,7 @@ func testGetClientCertificate(t *testing.T, version uint16) { serverConfig.RootCAs = x509.NewCertPool() serverConfig.RootCAs.AddCert(issuer) serverConfig.ClientCAs = serverConfig.RootCAs - serverConfig.Time = func() time.Time { return time.Unix(1476984729, 0) } + serverConfig.Time = testTime serverConfig.MaxVersion = version clientConfig := testConfig.Clone() @@ -2562,6 +2567,7 @@ func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) { ClientSessionCache: NewLRUClientSessionCache(32), ServerName: "example.golang", RootCAs: roots, + Time: testTime, } serverConfig := testConfig.Clone() serverConfig.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}} diff --git a/handshake_server_test.go b/handshake_server_test.go index 29a802d..f533023 100644 --- a/handshake_server_test.go +++ b/handshake_server_test.go @@ -519,6 +519,7 @@ func testCrossVersionResume(t *testing.T, version uint16) { serverConfig := &Config{ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, Certificates: testConfig.Certificates, + Time: testTime, } clientConfig := &Config{ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, @@ -526,6 +527,7 @@ func testCrossVersionResume(t *testing.T, version uint16) { ClientSessionCache: NewLRUClientSessionCache(1), ServerName: "servername", MinVersion: VersionTLS12, + Time: testTime, } // Establish a session at TLS 1.3. diff --git a/handshake_test.go b/handshake_test.go index 5a9c24f..ea8ac6f 100644 --- a/handshake_test.go +++ b/handshake_test.go @@ -522,6 +522,11 @@ func fromHex(s string) []byte { return b } +// testTime is 2016-10-20T17:32:09.000Z, which is within the validity period of +// [testRSACertificate], [testRSACertificateIssuer], [testRSA2048Certificate], +// [testRSA2048CertificateIssuer], and [testECDSACertificate]. +var testTime = func() time.Time { return time.Unix(1476984729, 0) } + var testRSACertificate = fromHex("3082024b308201b4a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301a310b3009060355040a1302476f310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a38193308190300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e041204109f91161f43433e49a6de6db680d79f60301b0603551d230414301280104813494d137e1631bba301d5acab6e7b30190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b0500038181009d30cc402b5b50a061cbbae55358e1ed8328a9581aa938a495a1ac315a1a84663d43d32dd90bf297dfd320643892243a00bccf9c7db74020015faad3166109a276fd13c3cce10c5ceeb18782f16c04ed73bbb343778d0c1cf10fa1d8408361c94c722b9daedb4606064df4c1b33ec0d1bd42d4dbfe3d1360845c21d33be9fae7") var testRSACertificateIssuer = fromHex("3082021930820182a003020102020900ca5e4e811a965964300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100d667b378bb22f34143b6cd2008236abefaf2852adf3ab05e01329e2c14834f5105df3f3073f99dab5442d45ee5f8f57b0111c8cb682fbb719a86944eebfffef3406206d898b8c1b1887797c9c5006547bb8f00e694b7a063f10839f269f2c34fff7a1f4b21fbcd6bfdfb13ac792d1d11f277b5c5b48600992203059f2a8f8cc50203010001a35d305b300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff30190603551d0e041204104813494d137e1631bba301d5acab6e7b300d06092a864886f70d01010b050003818100c1154b4bab5266221f293766ae4138899bd4c5e36b13cee670ceeaa4cbdf4f6679017e2fe649765af545749fe4249418a56bd38a04b81e261f5ce86b8d5c65413156a50d12449554748c59a30c515bc36a59d38bddf51173e899820b282e40aa78c806526fd184fb6b4cf186ec728edffa585440d2b3225325f7ab580e87dd76") diff --git a/tls_test.go b/tls_test.go index 51cd2b9..76a9a22 100644 --- a/tls_test.go +++ b/tls_test.go @@ -1158,8 +1158,6 @@ func TestConnectionState(t *testing.T) { rootCAs := x509.NewCertPool() rootCAs.AddCert(issuer) - now := func() time.Time { return time.Unix(1476984729, 0) } - const alpnProtocol = "golang" const serverName = "example.golang" var scts = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")} @@ -1175,7 +1173,7 @@ func TestConnectionState(t *testing.T) { } t.Run(name, func(t *testing.T) { config := &Config{ - Time: now, + Time: testTime, Rand: zeroSource{}, Certificates: make([]Certificate, 1), MaxVersion: v, @@ -1810,7 +1808,7 @@ func testVerifyCertificates(t *testing.T, version uint16) { var serverVerifyPeerCertificates, clientVerifyPeerCertificates bool clientConfig := testConfig.Clone() - clientConfig.Time = func() time.Time { return time.Unix(1476984729, 0) } + clientConfig.Time = testTime clientConfig.MaxVersion = version clientConfig.MinVersion = version clientConfig.RootCAs = rootCAs From ade44c2ba65d2723b8d27e31e169e6bc74ac7a01 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Mon, 30 Dec 2024 10:36:55 -0800 Subject: [PATCH 33/34] crypto/tls: properly return ECH retry configs When ECH is rejected, properly take retry configs from the encrypted extensions message. Also fix the bogo shim to properly test for this behavior. We should properly map the full BoringSSL -> Go errors so that we don't run into a similar failure in the future, but this is left for a follow up CL. Fixes #70915 Change-Id: Icc1878ff6f87df059e7b83e0a431f50f1fea833c Reviewed-on: https://go-review.googlesource.com/c/go/+/638583 Reviewed-by: Damien Neil Reviewed-by: Filippo Valsorda LUCI-TryBot-Result: Go LUCI --- bogo_config.json | 5 ++++- handshake_client.go | 1 + handshake_client_tls13.go | 16 ++++++++-------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/bogo_config.json b/bogo_config.json index 1c313ec..32969a3 100644 --- a/bogo_config.json +++ b/bogo_config.json @@ -246,5 +246,8 @@ 25, 29, 4588 - ] + ], + "ErrorMap": { + ":ECH_REJECTED:": "tls: server rejected ECH" + } } diff --git a/handshake_client.go b/handshake_client.go index 3bf703e..38bd417 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -260,6 +260,7 @@ type echClientContext struct { kdfID uint16 aeadID uint16 echRejected bool + retryConfigs []byte } func (c *Conn) clientHandshake(ctx context.Context) (err error) { diff --git a/handshake_client_tls13.go b/handshake_client_tls13.go index 38c6025..c0396e7 100644 --- a/handshake_client_tls13.go +++ b/handshake_client_tls13.go @@ -85,7 +85,6 @@ func (hs *clientHandshakeStateTLS13) handshake() error { } } - var echRetryConfigList []byte if hs.echContext != nil { confTranscript := cloneHash(hs.echContext.innerTranscript, hs.suite.hash) confTranscript.Write(hs.serverHello.original[:30]) @@ -114,9 +113,6 @@ func (hs *clientHandshakeStateTLS13) handshake() error { } } else { hs.echContext.echRejected = true - // If the server sent us retry configs, we'll return these to - // the user so they can update their Config. - echRetryConfigList = hs.serverHello.encryptedClientHello } } @@ -155,7 +151,7 @@ func (hs *clientHandshakeStateTLS13) handshake() error { if hs.echContext != nil && hs.echContext.echRejected { c.sendAlert(alertECHRequired) - return &ECHRejectionError{echRetryConfigList} + return &ECHRejectionError{hs.echContext.retryConfigs} } c.isHandshakeComplete.Store(true) @@ -601,9 +597,13 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error { return errors.New("tls: server accepted 0-RTT with the wrong ALPN") } } - if hs.echContext != nil && !hs.echContext.echRejected && encryptedExtensions.echRetryConfigs != nil { - c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: server sent encrypted client hello retry configs after accepting encrypted client hello") + if hs.echContext != nil { + if hs.echContext.echRejected { + hs.echContext.retryConfigs = encryptedExtensions.echRetryConfigs + } else if encryptedExtensions.echRetryConfigs != nil { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: server sent encrypted client hello retry configs after accepting encrypted client hello") + } } return nil From 51c7999d8157c39297b20d7235c33e971ad7859b Mon Sep 17 00:00:00 2001 From: thekuwayama Date: Mon, 30 Dec 2024 19:28:35 +0000 Subject: [PATCH 34/34] crypto/tls: send illegal_parameter on invalid ECHClientHello.type The spec indicates that if a client sends an invalid ECHClientHello.type in ClientHelloOuter, the server will abort the handshake with a decode_error alert. Define errInvalidECHExt for invalid ECHClientHello.type. If parseECHExt returns an errInvalidECHExt error, Conn now sends an illegal_parameter alert. Fixes #71061. Change-Id: I240241fe8bbe3e77d6ad1af989794647bfa2ff87 GitHub-Last-Rev: 3d6c233ccd401453bfb1a4fc97fa5deeb5b2fbc8 GitHub-Pull-Request: golang/go#71062 Reviewed-on: https://go-review.googlesource.com/c/go/+/639235 Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker --- ech.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/ech.go b/ech.go index 55d5217..d9795b4 100644 --- a/ech.go +++ b/ech.go @@ -378,7 +378,7 @@ func decodeInnerClientHello(outer *clientHelloMsg, encoded []byte) (*clientHello } if !bytes.Equal(inner.encryptedClientHello, []byte{uint8(innerECHExt)}) { - return nil, errors.New("tls: client sent invalid encrypted_client_hello extension") + return nil, errInvalidECHExt } if len(inner.supportedVersions) != 1 || (len(inner.supportedVersions) >= 1 && inner.supportedVersions[0] != VersionTLS13) { @@ -481,6 +481,7 @@ func (e *ECHRejectionError) Error() string { } var errMalformedECHExt = errors.New("tls: malformed encrypted_client_hello extension") +var errInvalidECHExt = errors.New("tls: client sent invalid encrypted_client_hello extension") type echExtType uint8 @@ -507,7 +508,7 @@ func parseECHExt(ext []byte) (echType echExtType, cs echCipher, configID uint8, return echType, cs, 0, nil, nil, nil } if echType != outerECHExt { - err = errMalformedECHExt + err = errInvalidECHExt return } if !s.ReadUint16(&cs.KDFID) { @@ -549,8 +550,13 @@ func marshalEncryptedClientHelloConfigList(configs []EncryptedClientHelloKey) ([ func (c *Conn) processECHClientHello(outer *clientHelloMsg) (*clientHelloMsg, *echServerContext, error) { echType, echCiphersuite, configID, encap, payload, err := parseECHExt(outer.encryptedClientHello) if err != nil { - c.sendAlert(alertDecodeError) - return nil, nil, errors.New("tls: client sent invalid encrypted_client_hello extension") + if errors.Is(err, errInvalidECHExt) { + c.sendAlert(alertIllegalParameter) + } else { + c.sendAlert(alertDecodeError) + } + + return nil, nil, errInvalidECHExt } if echType == innerECHExt { @@ -597,7 +603,7 @@ func (c *Conn) processECHClientHello(outer *clientHelloMsg) (*clientHelloMsg, *e echInner, err := decodeInnerClientHello(outer, encodedInner) if err != nil { c.sendAlert(alertIllegalParameter) - return nil, nil, errors.New("tls: client sent invalid encrypted_client_hello extension") + return nil, nil, errInvalidECHExt } c.echAccepted = true