sync: merge changes from go 1.24.0

This commit is contained in:
Mingye Chen 2025-03-01 00:13:08 -07:00
commit a99feacec2
50 changed files with 2505 additions and 2734 deletions

View file

@ -291,9 +291,11 @@ 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) {
continue
}
// [uTLS] SECTION BEGIN
// if fips140tls.Required() && !isSupportedSignatureAlgorithm(preferredAlg, defaultSupportedSignatureAlgorithmsFIPS) {
// continue
// }
// [uTLS] SECTION END
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
return preferredAlg, nil
}

View file

@ -9,6 +9,7 @@ import (
"testing"
circlPki "github.com/cloudflare/circl/pki"
"github.com/refraction-networking/utls/internal/fips140tls"
)
func TestSignatureSelection(t *testing.T) {
@ -59,6 +60,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)

View file

@ -10,8 +10,6 @@ import (
"crypto/cipher"
"crypto/des"
"crypto/hmac"
// "crypto/internal/boring"
"crypto/rc4"
"crypto/sha1"
"crypto/sha256"
@ -236,7 +234,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
@ -368,15 +366,13 @@ var tdesCiphers = map[uint16]bool{
}
var (
hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
// 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
// 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{
@ -526,7 +522,10 @@ func aeadAESGCM(key, noncePrefix []byte) aead {
aead, err = boring.NewGCMTLS(aes)
} else {
boring.Unreachable()
// [uTLS] SECTION BEGIN
// aead, err = gcm.NewGCMForTLS12(aes.(*fipsaes.Block))
aead, err = cipher.NewGCM(aes)
// [uTLS] SECTION END
}
if err != nil {
panic(err)
@ -555,7 +554,16 @@ 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()
// [uTLS] SECTION BEGIN
// aead, err = gcm.NewGCMForTLS13(aes.(*fipsaes.Block))
aead, err = cipher.NewGCM(aes)
// [uTLS] SECTION END
}
if err != nil {
panic(err)
}

216
common.go
View file

@ -25,6 +25,8 @@ import (
"sync"
"time"
_ "unsafe" // for linkname
"github.com/refraction-networking/utls/internal/fips140tls"
)
const (
@ -145,17 +147,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
@ -430,9 +436,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.
@ -459,6 +468,10 @@ type ClientHelloInfo struct {
// might be rejected if used.
SupportedVersions []uint16
// Extensions lists the IDs of the extensions presented by the client
// in the ClientHello.
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.
@ -808,14 +821,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
// PQSignatureSchemesEnabled controls whether additional post-quantum
@ -843,8 +857,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.
@ -853,7 +869,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.
//
@ -862,9 +878,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 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.
//
// Unlike VerifyPeerCertificate and VerifyConnection, normal certificate
// verification will not be performed before calling
@ -876,6 +894,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
@ -900,6 +932,24 @@ type Config struct {
ECHConfigs []ECHConfig // [uTLS]
}
// 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.
@ -981,6 +1031,7 @@ func (c *Config) Clone() *Config {
KeyLogWriter: c.KeyLogWriter,
EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList,
EncryptedClientHelloRejectionVerify: c.EncryptedClientHelloRejectionVerify,
EncryptedClientHelloKeys: c.EncryptedClientHelloKeys,
sessionTicketKeys: c.sessionTicketKeys,
autoSessionTicketKeys: c.autoSessionTicketKeys,
@ -1133,17 +1184,21 @@ func (c *Config) time() time.Time {
func (c *Config) cipherSuites() []uint16 {
if c.CipherSuites == nil {
if needFIPS() {
return defaultCipherSuitesFIPS
}
// [uTLS] SECTION BEGIN
// if fips140tls.Required() {
// return defaultCipherSuitesFIPS
// }
// [uTLS] SECTION END
return defaultCipherSuites()
}
if needFIPS() {
cipherSuites := slices.Clone(c.CipherSuites)
return slices.DeleteFunc(cipherSuites, func(id uint16) bool {
return !slices.Contains(defaultCipherSuitesFIPS, id)
})
}
// [uTLS] SECTION BEGIN
// if fips140tls.Required() {
// cipherSuites := slices.Clone(c.CipherSuites)
// return slices.DeleteFunc(cipherSuites, func(id uint16) bool {
// return !slices.Contains(defaultCipherSuitesFIPS, id)
// })
// }
// [uTLS] SECTION END
return c.CipherSuites
}
@ -1164,9 +1219,11 @@ const roleServer = false
func (c *Config) supportedVersions(isClient bool) []uint16 {
versions := make([]uint16, 0, len(supportedVersions))
for _, v := range supportedVersions {
if needFIPS() && !slices.Contains(defaultSupportedVersionsFIPS, v) {
continue
}
// [uTLS] SECTION BEGIN
// if fips140tls.Required() && !slices.Contains(defaultSupportedVersionsFIPS, v) {
// continue
// }
// [uTLS] SECTION END
if (c == nil || c.MinVersion == 0) && v < VersionTLS12 {
// [uTLS SECTION BEGIN]
// Disable unsupported godebug package
@ -1216,22 +1273,20 @@ func supportedVersionsFromMax(maxVersion uint16) []uint16 {
func (c *Config) curvePreferences(version uint16) []CurveID {
var curvePreferences []CurveID
// [uTLS] SECTION BEGIN
// if fips140tls.Required() {
// curvePreferences = slices.Clone(defaultCurvePreferencesFIPS)
// } else {
curvePreferences = defaultCurvePreferences()
// }
// [uTLS] SECTION END
if c != nil && len(c.CurvePreferences) != 0 {
curvePreferences = slices.Clone(c.CurvePreferences)
if needFIPS() {
return slices.DeleteFunc(curvePreferences, func(c CurveID) bool {
return !slices.Contains(defaultCurvePreferencesFIPS, c)
})
}
} else if needFIPS() {
curvePreferences = slices.Clone(defaultCurvePreferencesFIPS)
} else {
curvePreferences = defaultCurvePreferences()
curvePreferences = slices.DeleteFunc(curvePreferences, func(x CurveID) bool {
return !slices.Contains(c.CurvePreferences, x)
})
}
if version < VersionTLS13 {
return slices.DeleteFunc(curvePreferences, func(c CurveID) bool {
return c == x25519Kyber768Draft00
})
curvePreferences = slices.DeleteFunc(curvePreferences, isTLS13OnlyKeyExchange)
}
return curvePreferences
}
@ -1695,10 +1750,12 @@ func unexpectedMessageError(wanted, got any) error {
// supportedSignatureAlgorithms returns the supported signature algorithms.
func supportedSignatureAlgorithms() []SignatureScheme {
if !needFIPS() {
return defaultSupportedSignatureAlgorithms
}
return defaultSupportedSignatureAlgorithmsFIPS
// [uTLS] SECTION BEGIN
// if !fips140tls.Required() {
return defaultSupportedSignatureAlgorithms
// }
// return defaultSupportedSignatureAlgorithmsFIPS
// [uTLS] SECTION END
}
func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool {
@ -1724,3 +1781,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
}

View file

@ -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) + ")"

View file

@ -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}

View file

@ -12,17 +12,18 @@ import (
// Defaults are collected in this file to allow distributions to more easily patch
// them to apply local policies.
// var tlskyber = godebug.New("tlskyber") [uTLS]
// var tlsmlkem = godebug.New("tlsmlkem") [uTLS]
// defaultCurvePreferences is the default set of supported key exchanges, as
// well as the preference order.
func defaultCurvePreferences() []CurveID {
// [uTLS section begins]
// if tlskyber.Value() == "0" {
// if tlsmlkem.Value() == "0" {
// return []CurveID{X25519, CurveP256, CurveP384, CurveP521}
// }
// [uTLS section ends]
// 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
@ -98,13 +99,18 @@ var defaultCipherSuitesTLS13NoAES = []uint16{
TLS_AES_256_GCM_SHA384,
}
// 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,
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.
@ -117,7 +123,6 @@ var defaultSupportedSignatureAlgorithmsFIPS = []SignatureScheme{
PKCS1WithSHA384,
ECDSAWithP384AndSHA384,
PKCS1WithSHA512,
ECDSAWithP521AndSHA512,
}
// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites.
@ -126,8 +131,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.

478
ech.go
View file

@ -5,7 +5,10 @@
package tls
import (
"bytes"
"errors"
"fmt"
"slices"
"strings"
"github.com/refraction-networking/utls/internal/hpke"
@ -13,6 +16,18 @@ import (
"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
@ -41,12 +56,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
@ -56,69 +136,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
}
@ -196,6 +225,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, errInvalidECHExt
}
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
@ -207,7 +405,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
@ -282,3 +480,159 @@ type ECHRejectionError struct {
func (e *ECHRejectionError) Error() string {
return "tls: server rejected ECH"
}
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
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 = errInvalidECHExt
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 {
if errors.Is(err, errInvalidECHExt) {
c.sendAlert(alertIllegalParameter)
} else {
c.sendAlert(alertDecodeError)
}
return nil, nil, errInvalidECHExt
}
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, errInvalidECHExt
}
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()
}

View file

@ -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()
}

View file

@ -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")
}
}

View file

@ -10,6 +10,7 @@ import (
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/mlkem"
"crypto/rsa"
"crypto/subtle"
"crypto/x509"
@ -18,14 +19,14 @@ import (
"hash"
"io"
"net"
"slices"
"strings"
"time"
"github.com/refraction-networking/utls/internal/hpke"
"github.com/refraction-networking/utls/internal/byteorder"
"github.com/refraction-networking/utls/internal/mlkem768"
"github.com/refraction-networking/utls/internal/fips140tls"
"github.com/refraction-networking/utls/internal/hpke"
"github.com/refraction-networking/utls/internal/tls13"
circlSign "github.com/cloudflare/circl/sign"
)
@ -46,7 +47,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
// [UTLS SECTION START]
@ -149,35 +150,44 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCon
if len(hello.supportedVersions) == 1 {
hello.cipherSuites = nil
}
if hasAESGCMHardwareSupport {
if fips140tls.Required() {
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 {
// 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
}
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.NewKeyFromSeed(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()...)},
{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 {
@ -202,7 +212,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")
@ -218,7 +228,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
@ -247,7 +257,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
@ -256,6 +266,7 @@ type echContext struct {
kdfID uint16
aeadID uint16
echRejected bool
retryConfigs []byte
}
func (c *Conn) clientHandshake(ctx context.Context) (err error) {
@ -327,7 +338,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)
}
@ -387,7 +398,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) {
// [UTLS SECTION START]
if c.utls.sessionController != nil {
c.utls.sessionController.onEnterLoadSessionCheck()
@ -534,8 +545,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()
// [UTLS SECTION START]
if c.utls.sessionController != nil && !c.utls.sessionController.shouldLoadSessionWriteBinders() {
return
@ -662,11 +673,11 @@ func (hs *clientHandshakeState) pickCipherSuite() error {
}
// [UTLS SECTION START]
// 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()
// }
@ -741,11 +752,11 @@ 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 */ {
c.curveID = CurveID(byteorder.BeUint16(skx.key[1:]))
c.curveID = CurveID(byteorder.BEUint16(skx.key[1:]))
}
msg, err = c.readHandshake(&hs.finishedHash)
@ -969,7 +980,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 {
@ -1162,8 +1173,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}
@ -1192,8 +1208,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}

View file

@ -32,6 +32,7 @@ import (
"time"
"github.com/refraction-networking/utls/internal/byteorder"
"github.com/refraction-networking/utls/internal/fips140tls"
)
// Note: see comment in handshake_test.go for details of how the reference
@ -208,7 +209,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,
})
}
@ -434,7 +435,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 {
@ -849,14 +850,17 @@ 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,
Time: testTime, // [uTLS]
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(testRSACertificateIssuer)
issuer, err := x509.ParseCertificate(testRSA2048CertificateIssuer)
if err != nil {
panic(err)
}
@ -866,11 +870,11 @@ 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",
Time: testTime, // [uTLS]
Time: testTime,
}
testResumeState := func(test string, didResume bool) {
@ -917,7 +921,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 testTime().Add(24*time.Hour + time.Minute) } // [uTLS]
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")
@ -925,13 +929,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 testTime().Add(24*8*time.Hour + time.Minute) } // [uTLS]
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 = testTime // reset the time back // [uTLS]
serverConfig.Time = testTime // reset the time back
key1 := randomKey()
serverConfig.SetSessionTicketKeys([][32]byte{key1})
@ -948,11 +952,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 testTime().Add(24*time.Hour + time.Minute) } // [uTLS]
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 testTime().Add(24*8*time.Hour + 2*time.Minute) } // [uTLS]
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")
@ -960,7 +964,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 testTime().Add(d) } // [uTLS]
serverConfig.Time = func() time.Time { return testTime().Add(d) }
deleteTicket()
testResumeState("GetFreshSessionTicket", false)
for i := 0; i < 13; i++ {
@ -971,7 +975,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 + time.Minute // [uTLS]
d += 12*time.Hour + time.Minute
if version == VersionTLS13 {
testResumeState("ExpiredSessionTicket", true)
} else {
@ -985,9 +989,9 @@ 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,
Time: testTime, // [uTLS]
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})
@ -996,7 +1000,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)
}
@ -1012,8 +1016,8 @@ 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,
Time: testTime, // [uTLS]
Certificates: testCertificates,
Time: testTime,
}
testResumeState("InitialHandshake", false)
testResumeState("WithHelloRetryRequest", true)
@ -1021,9 +1025,9 @@ 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,
Time: testTime, // [uTLS]
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
Certificates: testCertificates,
Time: testTime,
}
}
@ -1278,7 +1282,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()
@ -1298,7 +1302,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)
@ -1314,7 +1318,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)
}
}
@ -1730,7 +1734,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)
}
@ -1741,8 +1748,8 @@ func testVerifyConnection(t *testing.T, version uint16) {
serverConfig := &Config{
MaxVersion: version,
Certificates: []Certificate{testConfig.Certificates[0]},
Time: testTime, // [uTLS]
Certificates: testCertificates,
Time: testTime,
ClientCAs: rootCAs,
NextProtos: []string{"protocol1"},
}
@ -1755,8 +1762,8 @@ func testVerifyConnection(t *testing.T, version uint16) {
ClientSessionCache: NewLRUClientSessionCache(32),
RootCAs: rootCAs,
ServerName: "example.golang",
Certificates: []Certificate{testConfig.Certificates[0]},
Time: testTime, // [uTLS]
Certificates: testCertificates,
Time: testTime,
NextProtos: []string{"protocol1"},
}
test.configureClient(clientConfig, &clientCalled)
@ -1791,7 +1798,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)
}
@ -1799,8 +1807,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,11 +2052,11 @@ 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{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)
@ -2061,9 +2067,10 @@ 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
config.Time = testTime
config.MaxVersion = version
test.configureClient(config, &clientCalled)
clientErr := Client(c, config).Handshake()
@ -2344,8 +2351,8 @@ var getClientCertificateTests = []struct {
panic("empty AcceptableCAs")
}
cert := &Certificate{
Certificate: [][]byte{testRSACertificate},
PrivateKey: testRSAPrivateKey,
Certificate: [][]byte{testRSA2048Certificate},
PrivateKey: testRSA2048PrivateKey,
}
return cert, nil
}
@ -2365,25 +2372,34 @@ 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)
serverConfig.ClientCAs = serverConfig.RootCAs
serverConfig.Time = func() time.Time { return time.Unix(1476984729, 0) }
serverConfig.Time = testTime
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
@ -2522,11 +2538,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")
}
}
@ -2536,7 +2556,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")
}
@ -2547,9 +2568,10 @@ func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) {
ClientSessionCache: NewLRUClientSessionCache(32),
ServerName: "example.golang",
RootCAs: roots,
Time: testTime, // [uTLS]
Time: testTime,
}
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}}
@ -2684,11 +2706,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)
}
}

View file

@ -10,6 +10,7 @@ import (
"crypto"
"crypto/ecdh"
"crypto/hmac"
"crypto/mlkem"
"crypto/rsa"
"crypto/subtle"
"errors"
@ -18,9 +19,9 @@ import (
"slices"
"time"
"github.com/refraction-networking/utls/internal/mlkem768"
"github.com/cloudflare/circl/kem"
"github.com/refraction-networking/utls/internal/hkdf"
"github.com/refraction-networking/utls/internal/tls13"
)
// [uTLS SECTION START]
@ -61,10 +62,10 @@ func (ksp *KeySharesParameters) GetEcdhePubkey(curveID CurveID) (params *ecdh.Pu
}
func (ksp *KeySharesParameters) AddKemKeypair(curveID CurveID, kemKey kem.PrivateKey, kemPubKey kem.PublicKey) {
if curveID == x25519Kyber768Draft00 { // only store for x25519Kyber768Draft00
ksp.kemPrivKeymap[curveID] = kemKey
ksp.kemPubKeymap[curveID] = kemPubKey
}
// if curveID == x25519Kyber768Draft00 { // only store for x25519Kyber768Draft00
// ksp.kemPrivKeymap[curveID] = kemKey
// ksp.kemPubKeymap[curveID] = kemPubKey
// }
}
func (ksp *KeySharesParameters) GetKemKey(curveID CurveID) (kemKey kem.PrivateKey, ok bool) {
@ -88,7 +89,7 @@ type clientHandshakeStateTLS13 struct {
keySharesParams *KeySharesParameters // [uTLS] support both ecdhe and kem
session *SessionState
earlySecret []byte
earlySecret *tls13.EarlySecret
binderKey []byte
certReq *certificateRequestMsgTLS13
@ -96,10 +97,10 @@ type clientHandshakeStateTLS13 struct {
sentDummyCCS bool
suite *cipherSuiteTLS13
transcript hash.Hash
masterSecret []byte
masterSecret *tls13.MasterSecret
trafficSecret []byte // client_application_traffic_secret_0
echContext *echContext
echContext *echClientContext
uconn *UConn // [uTLS]
}
@ -109,10 +110,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 {
@ -121,21 +118,21 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
}
// [uTLS SECTION START]
if hs.keyShareKeys == nil {
// set echdheParams to what we received from server
if ecdheKey, ok := hs.keySharesParams.GetEcdheKey(hs.serverHello.serverShare.group); ok {
hs.keyShareKeys.ecdhe = ecdheKey
hs.keyShareKeys.curveID = hs.serverHello.serverShare.group
}
// set kemParams to what we received from server
if kemKey, ok := hs.keySharesParams.GetKemKey(hs.serverHello.serverShare.group); ok {
if kyberKey, ecdhKey, err := mlkemCirclToGo(kemKey); err == nil {
hs.keyShareKeys.kyber = kyberKey
hs.keyShareKeys.ecdhe = ecdhKey
hs.keyShareKeys.curveID = hs.serverHello.serverShare.group
}
}
}
// if hs.keyShareKeys == nil {
// // set echdheParams to what we received from server
// if ecdheKey, ok := hs.keySharesParams.GetEcdheKey(hs.serverHello.serverShare.group); ok {
// hs.keyShareKeys.ecdhe = ecdheKey
// hs.keyShareKeys.curveID = hs.serverHello.serverShare.group
// }
// // set kemParams to what we received from server
// if kemKey, ok := hs.keySharesParams.GetKemKey(hs.serverHello.serverShare.group); ok {
// if kyberKey, ecdhKey, err := mlkemCirclToGo(kemKey); err == nil {
// hs.keyShareKeys.kyber = kyberKey
// hs.keyShareKeys.ecdhe = ecdhKey
// hs.keyShareKeys.curveID = hs.serverHello.serverShare.group
// }
// }
// }
// [uTLS SECTION END]
// Consistency check on the presence of a keyShare and its parameters.
@ -169,14 +166,13 @@ 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])
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,
@ -189,7 +185,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 {
@ -198,9 +194,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
}
}
@ -244,7 +237,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)
@ -357,8 +350,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,
@ -377,7 +370,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
@ -411,12 +404,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")
@ -630,12 +622,12 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
c := hs.c
ecdhePeerData := hs.serverHello.serverShare.data
if hs.serverHello.serverShare.group == x25519Kyber768Draft00 {
if len(ecdhePeerData) != x25519PublicKeySize+mlkem768.CiphertextSize {
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 {
@ -647,33 +639,30 @@ 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
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 {
@ -695,8 +684,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
}
@ -766,9 +754,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 ECH retry configs after accepting ECH")
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
@ -920,10 +912,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)
@ -1030,8 +1020,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 {
@ -1075,7 +1064,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()

View file

@ -98,6 +98,8 @@ type clientHelloMsg struct {
pskBinders [][]byte
quicTransportParameters []byte
encryptedClientHello []byte
// extensions are only populated on the server-side of a handshake
extensions []uint16
// [uTLS]
nextProtoNeg bool
@ -477,6 +479,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
return false
}
seenExts[extension] = true
m.extensions = append(m.extensions, extension)
switch extension {
case extensionServerName:
@ -669,6 +672,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

View file

@ -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
@ -220,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)
}

View file

@ -43,7 +43,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
}
@ -53,6 +53,7 @@ func (c *Conn) serverHandshake(ctx context.Context) error {
c: c,
ctx: ctx,
clientHello: clientHello,
echContext: ech,
}
return hs.handshake()
}
@ -134,17 +135,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
@ -153,7 +164,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
}
@ -167,12 +178,24 @@ 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")
}
// [UTLS SECTION BEGIN]
// Disable unsupported godebug package
// if c.config.MinVersion == 0 && c.vers < VersionTLS12 {
@ -181,7 +204,7 @@ func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
// }
// [UTLS SECTION END]
return clientHello, nil
return clientHello, ech, nil
}
func (hs *serverHandshakeState) processClientHello() error {
@ -381,11 +404,11 @@ func (hs *serverHandshakeState) pickCipherSuite() error {
// [UTLS SECTION BEGIN]
// Disable unsupported godebug package
// 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()
// }
@ -603,7 +626,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
@ -691,7 +714,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 {
@ -936,7 +959,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
@ -976,6 +1003,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,

View file

@ -23,11 +23,15 @@ import (
"runtime"
"slices"
"strings"
"sync/atomic"
"testing"
"time"
"github.com/refraction-networking/utls/internal/fips140tls"
)
func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
t.Helper()
testClientHelloFailure(t, serverConfig, m, "")
}
@ -52,12 +56,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()
@ -116,7 +121,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},
@ -126,9 +131,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")
@ -136,7 +141,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},
@ -160,9 +165,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},
@ -186,9 +191,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},
@ -208,6 +213,8 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) {
}
func TestRenegotiationExtension(t *testing.T) {
skipFIPS(t) // #70505
clientHello := &clientHelloMsg{
vers: VersionTLS12,
compressionMethods: []uint8{compressionNone},
@ -260,6 +267,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{
@ -321,13 +330,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,
@ -341,7 +355,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)
@ -354,9 +370,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 {
@ -431,6 +448,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},
@ -499,16 +518,17 @@ 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,
Time: testTime,
}
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",
MinVersion: VersionTLS12,
Time: testTime, // [uTLS]
Time: testTime,
}
// Establish a session at TLS 1.3.
@ -922,22 +942,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.X25519().GenerateKey(rand.Reader)
clientHello := &clientHelloMsg{
vers: VersionTLS12,
random: make([]byte, 32),
supportedVersions: []uint16{VersionTLS13},
cipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256},
compressionMethods: []uint8{compressionNone},
keyShares: []keyShare{{group: X25519, 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"}
@ -1067,6 +1071,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.P256().GenerateKey(rand.Reader)
clientHello := &clientHelloMsg{
vers: vers,
random: make([]byte, 32),
cipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
compressionMethods: []uint8{compressionNone},
serverName: "test",
keyShares: []keyShare{{group: CurveP256, data: pk.PublicKey().Bytes()}},
supportedCurves: []CurveID{CurveP256},
supportedSignatureAlgorithms: []SignatureScheme{ECDSAWithP256AndSHA256},
}
// 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) {
@ -1078,9 +1141,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",
}
@ -1099,9 +1162,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)
@ -1111,9 +1174,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")
@ -1436,9 +1499,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,
}
@ -1458,7 +1521,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,
@ -1694,7 +1757,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()
@ -1716,6 +1779,8 @@ func TestMultipleCertificates(t *testing.T) {
}
func TestAESCipherReordering(t *testing.T) {
skipFIPS(t) // No CHACHA20_POLY1305 for FIPS.
currentAESSupport := hasAESGCMHardwareSupport
defer func() { hasAESGCMHardwareSupport = currentAESSupport }()
@ -1859,6 +1924,8 @@ func TestAESCipherReordering(t *testing.T) {
}
func TestAESCipherReorderingTLS13(t *testing.T) {
skipFIPS(t) // No CHACHA20_POLY1305 for FIPS.
currentAESSupport := hasAESGCMHardwareSupport
defer func() { hasAESGCMHardwareSupport = currentAESSupport }()

View file

@ -9,15 +9,20 @@ import (
"context"
"crypto"
"crypto/hmac"
"crypto/mlkem"
"crypto/rsa"
"errors"
"hash"
"io"
"slices"
"sort"
"time"
"github.com/refraction-networking/utls/internal/byteorder"
"github.com/refraction-networking/utls/internal/mlkem768"
"github.com/refraction-networking/utls/internal/fips140tls"
"github.com/refraction-networking/utls/internal/hkdf"
"github.com/refraction-networking/utls/internal/hpke"
"github.com/refraction-networking/utls/internal/tls13"
)
// maxClientPSKIdentities is the number of client PSK identities the server will
@ -25,6 +30,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
@ -36,23 +53,19 @@ type serverHandshakeStateTLS13 struct {
suite *cipherSuiteTLS13
cert *Certificate
sigAlg SignatureScheme
selectedGroup CurveID
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
echContext *echServerContext
}
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
@ -167,6 +180,9 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error {
if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
preferenceList = defaultCipherSuitesTLS13NoAES
}
if fips140tls.Required() {
preferenceList = defaultCipherSuitesTLS13FIPS
}
for _, suiteID := range preferenceList {
hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID)
if hs.suite != nil {
@ -181,37 +197,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 {
@ -223,13 +247,13 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error {
ecdhGroup := selectedGroup
ecdhData := clientKeyShare.data
if selectedGroup == x25519Kyber768Draft00 {
if selectedGroup == X25519MLKEM768 {
ecdhGroup = X25519
if len(ecdhData) != x25519PublicKeySize+mlkem768.EncapsulationKeySize {
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)
@ -251,14 +275,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...)
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
// 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)
@ -385,8 +419,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 {
@ -414,7 +448,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)
}
@ -532,6 +566,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
}
@ -552,6 +602,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")
@ -639,9 +728,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
}
@ -652,16 +759,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 {
@ -695,6 +799,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
}
@ -786,13 +900,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 {
@ -858,8 +969,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
@ -874,7 +984,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)
@ -909,7 +1019,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

View file

@ -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()
@ -521,19 +524,21 @@ func fromHex(s string) []byte {
return b
}
// [uTLS] SECTION BEGIN
// from go1.24
// 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) }
// [uTLS] SECTION END
var testRSACertificate = fromHex("3082024b308201b4a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301a310b3009060355040a1302476f310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a38193308190300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e041204109f91161f43433e49a6de6db680d79f60301b0603551d230414301280104813494d137e1631bba301d5acab6e7b30190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b0500038181009d30cc402b5b50a061cbbae55358e1ed8328a9581aa938a495a1ac315a1a84663d43d32dd90bf297dfd320643892243a00bccf9c7db74020015faad3166109a276fd13c3cce10c5ceeb18782f16c04ed73bbb343778d0c1cf10fa1d8408361c94c722b9daedb4606064df4c1b33ec0d1bd42d4dbfe3d1360845c21d33be9fae7")
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.

View file

@ -6,30 +6,30 @@
// little and big endian integer types from/to byte slices.
package byteorder
func LeUint16(b []byte) uint16 {
func LEUint16(b []byte) uint16 {
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint16(b[0]) | uint16(b[1])<<8
}
func LePutUint16(b []byte, v uint16) {
func LEPutUint16(b []byte, v uint16) {
_ = b[1] // early bounds check to guarantee safety of writes below
b[0] = byte(v)
b[1] = byte(v >> 8)
}
func LeAppendUint16(b []byte, v uint16) []byte {
func LEAppendUint16(b []byte, v uint16) []byte {
return append(b,
byte(v),
byte(v>>8),
)
}
func LeUint32(b []byte) uint32 {
func LEUint32(b []byte) uint32 {
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}
func LePutUint32(b []byte, v uint32) {
func LEPutUint32(b []byte, v uint32) {
_ = b[3] // early bounds check to guarantee safety of writes below
b[0] = byte(v)
b[1] = byte(v >> 8)
@ -37,7 +37,7 @@ func LePutUint32(b []byte, v uint32) {
b[3] = byte(v >> 24)
}
func LeAppendUint32(b []byte, v uint32) []byte {
func LEAppendUint32(b []byte, v uint32) []byte {
return append(b,
byte(v),
byte(v>>8),
@ -46,13 +46,13 @@ func LeAppendUint32(b []byte, v uint32) []byte {
)
}
func LeUint64(b []byte) uint64 {
func LEUint64(b []byte) uint64 {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
}
func LePutUint64(b []byte, v uint64) {
func LEPutUint64(b []byte, v uint64) {
_ = b[7] // early bounds check to guarantee safety of writes below
b[0] = byte(v)
b[1] = byte(v >> 8)
@ -64,7 +64,7 @@ func LePutUint64(b []byte, v uint64) {
b[7] = byte(v >> 56)
}
func LeAppendUint64(b []byte, v uint64) []byte {
func LEAppendUint64(b []byte, v uint64) []byte {
return append(b,
byte(v),
byte(v>>8),
@ -77,30 +77,30 @@ func LeAppendUint64(b []byte, v uint64) []byte {
)
}
func BeUint16(b []byte) uint16 {
func BEUint16(b []byte) uint16 {
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint16(b[1]) | uint16(b[0])<<8
}
func BePutUint16(b []byte, v uint16) {
func BEPutUint16(b []byte, v uint16) {
_ = b[1] // early bounds check to guarantee safety of writes below
b[0] = byte(v >> 8)
b[1] = byte(v)
}
func BeAppendUint16(b []byte, v uint16) []byte {
func BEAppendUint16(b []byte, v uint16) []byte {
return append(b,
byte(v>>8),
byte(v),
)
}
func BeUint32(b []byte) uint32 {
func BEUint32(b []byte) uint32 {
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
}
func BePutUint32(b []byte, v uint32) {
func BEPutUint32(b []byte, v uint32) {
_ = b[3] // early bounds check to guarantee safety of writes below
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)
@ -108,7 +108,7 @@ func BePutUint32(b []byte, v uint32) {
b[3] = byte(v)
}
func BeAppendUint32(b []byte, v uint32) []byte {
func BEAppendUint32(b []byte, v uint32) []byte {
return append(b,
byte(v>>24),
byte(v>>16),
@ -117,13 +117,13 @@ func BeAppendUint32(b []byte, v uint32) []byte {
)
}
func BeUint64(b []byte) uint64 {
func BEUint64(b []byte) uint64 {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
}
func BePutUint64(b []byte, v uint64) {
func BEPutUint64(b []byte, v uint64) {
_ = b[7] // early bounds check to guarantee safety of writes below
b[0] = byte(v >> 56)
b[1] = byte(v >> 48)
@ -135,7 +135,7 @@ func BePutUint64(b []byte, v uint64) {
b[7] = byte(v)
}
func BeAppendUint64(b []byte, v uint64) []byte {
func BEAppendUint64(b []byte, v uint64) []byte {
return append(b,
byte(v>>56),
byte(v>>48),

View file

@ -0,0 +1,5 @@
package fips140tls
func Required() bool {
return false
}

24
internal/hkdf/hkdf.go Normal file
View file

@ -0,0 +1,24 @@
package hkdf
import (
"crypto/hkdf"
"hash"
)
func Extract[H hash.Hash](h func() H, secret, salt []byte) []byte {
res, err := hkdf.Extract(h, secret, salt)
if err != nil {
panic(err)
}
return res
}
func Expand[H hash.Hash](h func() H, pseudorandomKey []byte, info string, keyLength int) []byte {
res, err := hkdf.Expand(h, pseudorandomKey, info, keyLength)
if err != nil {
panic(err)
}
return res
}

View file

@ -10,12 +10,12 @@ import (
"crypto/cipher"
"crypto/ecdh"
"crypto/rand"
"encoding/binary"
"errors"
"math/bits"
"github.com/refraction-networking/utls/internal/byteorder"
"github.com/refraction-networking/utls/internal/hkdf"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/hkdf"
)
// testingOnlyGenerateKey is only used during testing, to provide
@ -26,10 +26,10 @@ type hkdfKDF struct {
hash crypto.Hash
}
func (kdf *hkdfKDF) LabeledExtract(suiteID []byte, salt []byte, label string, inputKey []byte) []byte {
labeledIKM := make([]byte, 0, 7+len(suiteID)+len(label)+len(inputKey))
func (kdf *hkdfKDF) LabeledExtract(sid []byte, salt []byte, label string, inputKey []byte) []byte {
labeledIKM := make([]byte, 0, 7+len(sid)+len(label)+len(inputKey))
labeledIKM = append(labeledIKM, []byte("HPKE-v1")...)
labeledIKM = append(labeledIKM, suiteID...)
labeledIKM = append(labeledIKM, sid...)
labeledIKM = append(labeledIKM, label...)
labeledIKM = append(labeledIKM, inputKey...)
return hkdf.Extract(kdf.hash.New, labeledIKM, salt)
@ -37,17 +37,12 @@ func (kdf *hkdfKDF) LabeledExtract(suiteID []byte, salt []byte, label string, in
func (kdf *hkdfKDF) LabeledExpand(suiteID []byte, randomKey []byte, label string, info []byte, length uint16) []byte {
labeledInfo := make([]byte, 0, 2+7+len(suiteID)+len(label)+len(info))
labeledInfo = binary.BigEndian.AppendUint16(labeledInfo, length)
labeledInfo = byteorder.BEAppendUint16(labeledInfo, length)
labeledInfo = append(labeledInfo, []byte("HPKE-v1")...)
labeledInfo = append(labeledInfo, suiteID...)
labeledInfo = append(labeledInfo, label...)
labeledInfo = append(labeledInfo, info...)
out := make([]byte, length)
n, err := hkdf.Expand(kdf.hash.New, randomKey, labeledInfo).Read(out)
if err != nil || n != int(length) {
panic("hpke: LabeledExpand failed unexpectedly")
}
return out
return hkdf.Expand(kdf.hash.New, randomKey, string(labeledInfo), int(length))
}
// dhKEM implements the KEM specified in RFC 9180, Section 4.1.
@ -59,13 +54,17 @@ type dhKEM struct {
nSecret uint16
}
type KemID uint16
const DHKEM_X25519_HKDF_SHA256 = 0x0020
var SupportedKEMs = map[uint16]struct {
curve ecdh.Curve
hash crypto.Hash
nSecret uint16
}{
// RFC 9180 Section 7.1
0x0020: {ecdh.X25519(), crypto.SHA256, 32},
DHKEM_X25519_HKDF_SHA256: {ecdh.X25519(), crypto.SHA256, 32},
}
func newDHKem(kemID uint16) (*dhKEM, error) {
@ -76,7 +75,7 @@ func newDHKem(kemID uint16) (*dhKEM, error) {
return &dhKEM{
dh: suite.curve,
kdf: hkdfKDF{suite.hash},
suiteID: binary.BigEndian.AppendUint16([]byte("KEM"), kemID),
suiteID: byteorder.BEAppendUint16([]byte("KEM"), kemID),
nSecret: suite.nSecret,
}, nil
}
@ -108,9 +107,22 @@ func (dh *dhKEM) Encap(pubRecipient *ecdh.PublicKey) (sharedSecret []byte, encap
return dh.ExtractAndExpand(dhVal, kemContext), encPubEph, nil
}
type Sender struct {
func (dh *dhKEM) Decap(encPubEph []byte, secRecipient *ecdh.PrivateKey) ([]byte, error) {
pubEph, err := dh.dh.NewPublicKey(encPubEph)
if err != nil {
return nil, err
}
dhVal, err := secRecipient.ECDH(pubEph)
if err != nil {
return nil, err
}
kemContext := append(encPubEph, secRecipient.PublicKey().Bytes()...)
return dh.ExtractAndExpand(dhVal, kemContext), nil
}
type context struct {
aead cipher.AEAD
kem *dhKEM
sharedSecret []byte
@ -123,6 +135,14 @@ type Sender struct {
seqNum uint128
}
type Sender struct {
*context
}
type Receipient struct {
*context
}
var aesGCMNew = func(key []byte) (cipher.AEAD, error) {
block, err := aes.NewCipher(key)
if err != nil {
@ -131,102 +151,148 @@ var aesGCMNew = func(key []byte) (cipher.AEAD, error) {
return cipher.NewGCM(block)
}
type AEADID uint16
const (
AEAD_AES_128_GCM = 0x0001
AEAD_AES_256_GCM = 0x0002
AEAD_ChaCha20Poly1305 = 0x0003
)
var SupportedAEADs = map[uint16]struct {
keySize int
nonceSize int
aead func([]byte) (cipher.AEAD, error)
}{
// RFC 9180, Section 7.3
0x0001: {keySize: 16, nonceSize: 12, aead: aesGCMNew},
0x0002: {keySize: 32, nonceSize: 12, aead: aesGCMNew},
0x0003: {keySize: chacha20poly1305.KeySize, nonceSize: chacha20poly1305.NonceSize, aead: chacha20poly1305.New},
AEAD_AES_128_GCM: {keySize: 16, nonceSize: 12, aead: aesGCMNew},
AEAD_AES_256_GCM: {keySize: 32, nonceSize: 12, aead: aesGCMNew},
AEAD_ChaCha20Poly1305: {keySize: chacha20poly1305.KeySize, nonceSize: chacha20poly1305.NonceSize, aead: chacha20poly1305.New},
}
type KDFID uint16
const KDF_HKDF_SHA256 = 0x0001
var SupportedKDFs = map[uint16]func() *hkdfKDF{
// RFC 9180, Section 7.2
0x0001: func() *hkdfKDF { return &hkdfKDF{crypto.SHA256} },
KDF_HKDF_SHA256: func() *hkdfKDF { return &hkdfKDF{crypto.SHA256} },
}
func SetupSender(kemID, kdfID, aeadID uint16, pub crypto.PublicKey, info []byte) ([]byte, *Sender, error) {
suiteID := SuiteID(kemID, kdfID, aeadID)
kem, err := newDHKem(kemID)
if err != nil {
return nil, nil, err
}
pubRecipient, ok := pub.(*ecdh.PublicKey)
if !ok {
return nil, nil, errors.New("incorrect public key type")
}
sharedSecret, encapsulatedKey, err := kem.Encap(pubRecipient)
if err != nil {
return nil, nil, err
}
func newContext(sharedSecret []byte, kemID, kdfID, aeadID uint16, info []byte) (*context, error) {
sid := suiteID(kemID, kdfID, aeadID)
kdfInit, ok := SupportedKDFs[kdfID]
if !ok {
return nil, nil, errors.New("unsupported KDF id")
return nil, errors.New("unsupported KDF id")
}
kdf := kdfInit()
aeadInfo, ok := SupportedAEADs[aeadID]
if !ok {
return nil, nil, errors.New("unsupported AEAD id")
return nil, errors.New("unsupported AEAD id")
}
pskIDHash := kdf.LabeledExtract(suiteID, nil, "psk_id_hash", nil)
infoHash := kdf.LabeledExtract(suiteID, nil, "info_hash", info)
pskIDHash := kdf.LabeledExtract(sid, nil, "psk_id_hash", nil)
infoHash := kdf.LabeledExtract(sid, nil, "info_hash", info)
ksContext := append([]byte{0}, pskIDHash...)
ksContext = append(ksContext, infoHash...)
secret := kdf.LabeledExtract(suiteID, sharedSecret, "secret", nil)
secret := kdf.LabeledExtract(sid, sharedSecret, "secret", nil)
key := kdf.LabeledExpand(suiteID, secret, "key", ksContext, uint16(aeadInfo.keySize) /* Nk - key size for AEAD */)
baseNonce := kdf.LabeledExpand(suiteID, secret, "base_nonce", ksContext, uint16(aeadInfo.nonceSize) /* Nn - nonce size for AEAD */)
exporterSecret := kdf.LabeledExpand(suiteID, secret, "exp", ksContext, uint16(kdf.hash.Size()) /* Nh - hash output size of the kdf*/)
key := kdf.LabeledExpand(sid, secret, "key", ksContext, uint16(aeadInfo.keySize) /* Nk - key size for AEAD */)
baseNonce := kdf.LabeledExpand(sid, secret, "base_nonce", ksContext, uint16(aeadInfo.nonceSize) /* Nn - nonce size for AEAD */)
exporterSecret := kdf.LabeledExpand(sid, secret, "exp", ksContext, uint16(kdf.hash.Size()) /* Nh - hash output size of the kdf*/)
aead, err := aeadInfo.aead(key)
if err != nil {
return nil, nil, err
return nil, err
}
return encapsulatedKey, &Sender{
kem: kem,
return &context{
aead: aead,
sharedSecret: sharedSecret,
suiteID: suiteID,
suiteID: sid,
key: key,
baseNonce: baseNonce,
exporterSecret: exporterSecret,
}, nil
}
func (s *Sender) nextNonce() []byte {
nonce := s.seqNum.bytes()[16-s.aead.NonceSize():]
for i := range s.baseNonce {
nonce[i] ^= s.baseNonce[i]
func SetupSender(kemID, kdfID, aeadID uint16, pub *ecdh.PublicKey, info []byte) ([]byte, *Sender, error) {
kem, err := newDHKem(kemID)
if err != nil {
return nil, nil, err
}
// Message limit is, according to the RFC, 2^95+1, which
// is somewhat confusing, but we do as we're told.
if s.seqNum.bitLen() >= (s.aead.NonceSize()*8)-1 {
panic("message limit reached")
sharedSecret, encapsulatedKey, err := kem.Encap(pub)
if err != nil {
return nil, nil, err
}
context, err := newContext(sharedSecret, kemID, kdfID, aeadID, info)
if err != nil {
return nil, nil, err
}
return encapsulatedKey, &Sender{context}, nil
}
func SetupReceipient(kemID, kdfID, aeadID uint16, priv *ecdh.PrivateKey, info, encPubEph []byte) (*Receipient, error) {
kem, err := newDHKem(kemID)
if err != nil {
return nil, err
}
sharedSecret, err := kem.Decap(encPubEph, priv)
if err != nil {
return nil, err
}
context, err := newContext(sharedSecret, kemID, kdfID, aeadID, info)
if err != nil {
return nil, err
}
return &Receipient{context}, nil
}
func (ctx *context) nextNonce() []byte {
nonce := ctx.seqNum.bytes()[16-ctx.aead.NonceSize():]
for i := range ctx.baseNonce {
nonce[i] ^= ctx.baseNonce[i]
}
s.seqNum = s.seqNum.addOne()
return nonce
}
func (s *Sender) Seal(aad, plaintext []byte) ([]byte, error) {
func (ctx *context) incrementNonce() {
// Message limit is, according to the RFC, 2^95+1, which
// is somewhat confusing, but we do as we're told.
if ctx.seqNum.bitLen() >= (ctx.aead.NonceSize()*8)-1 {
panic("message limit reached")
}
ctx.seqNum = ctx.seqNum.addOne()
}
func (s *Sender) Seal(aad, plaintext []byte) ([]byte, error) {
ciphertext := s.aead.Seal(nil, s.nextNonce(), plaintext, aad)
s.incrementNonce()
return ciphertext, nil
}
func SuiteID(kemID, kdfID, aeadID uint16) []byte {
func (r *Receipient) Open(aad, ciphertext []byte) ([]byte, error) {
plaintext, err := r.aead.Open(nil, r.nextNonce(), ciphertext, aad)
if err != nil {
return nil, err
}
r.incrementNonce()
return plaintext, nil
}
func suiteID(kemID, kdfID, aeadID uint16) []byte {
suiteID := make([]byte, 0, 4+2+2+2)
suiteID = append(suiteID, []byte("HPKE")...)
suiteID = binary.BigEndian.AppendUint16(suiteID, kemID)
suiteID = binary.BigEndian.AppendUint16(suiteID, kdfID)
suiteID = binary.BigEndian.AppendUint16(suiteID, aeadID)
suiteID = byteorder.BEAppendUint16(suiteID, kemID)
suiteID = byteorder.BEAppendUint16(suiteID, kdfID)
suiteID = byteorder.BEAppendUint16(suiteID, aeadID)
return suiteID
}
@ -238,6 +304,14 @@ func ParseHPKEPublicKey(kemID uint16, bytes []byte) (*ecdh.PublicKey, error) {
return kemInfo.curve.NewPublicKey(bytes)
}
func ParseHPKEPrivateKey(kemID uint16, bytes []byte) (*ecdh.PrivateKey, error) {
kemInfo, ok := SupportedKEMs[kemID]
if !ok {
return nil, errors.New("unsupported KEM id")
}
return kemInfo.curve.NewPrivateKey(bytes)
}
type uint128 struct {
hi, lo uint64
}
@ -253,7 +327,7 @@ func (u uint128) bitLen() int {
func (u uint128) bytes() []byte {
b := make([]byte, 16)
binary.BigEndian.PutUint64(b[0:], u.hi)
binary.BigEndian.PutUint64(b[8:], u.lo)
byteorder.BEPutUint64(b[0:], u.hi)
byteorder.BEPutUint64(b[8:], u.lo)
return b
}

View file

@ -1,886 +0,0 @@
// Copyright 2023 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 mlkem768 implements the quantum-resistant key encapsulation method
// ML-KEM (formerly known as Kyber).
//
// Only the recommended ML-KEM-768 parameter set is provided.
//
// The version currently implemented is the one specified by [NIST FIPS 203 ipd],
// with the unintentional transposition of the matrix A reverted to match the
// behavior of [Kyber version 3.0]. Future versions of this package might
// introduce backwards incompatible changes to implement changes to FIPS 203.
//
// [Kyber version 3.0]: https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
// [NIST FIPS 203 ipd]: https://doi.org/10.6028/NIST.FIPS.203.ipd
package mlkem768
// This package targets security, correctness, simplicity, readability, and
// reviewability as its primary goals. All critical operations are performed in
// constant time.
//
// Variable and function names, as well as code layout, are selected to
// facilitate reviewing the implementation against the NIST FIPS 203 ipd
// document.
//
// Reviewers unfamiliar with polynomials or linear algebra might find the
// background at https://words.filippo.io/kyber-math/ useful.
import (
"crypto/rand"
"crypto/subtle"
"errors"
"github.com/refraction-networking/utls/internal/byteorder"
"golang.org/x/crypto/sha3"
)
const (
// ML-KEM global constants.
n = 256
q = 3329
log2q = 12
// ML-KEM-768 parameters. The code makes assumptions based on these values,
// they can't be changed blindly.
k = 3
η = 2
du = 10
dv = 4
// encodingSizeX is the byte size of a ringElement or nttElement encoded
// by ByteEncode_X (FIPS 203 (DRAFT), Algorithm 4).
encodingSize12 = n * log2q / 8
encodingSize10 = n * du / 8
encodingSize4 = n * dv / 8
encodingSize1 = n * 1 / 8
messageSize = encodingSize1
decryptionKeySize = k * encodingSize12
encryptionKeySize = k*encodingSize12 + 32
CiphertextSize = k*encodingSize10 + encodingSize4
EncapsulationKeySize = encryptionKeySize
DecapsulationKeySize = decryptionKeySize + encryptionKeySize + 32 + 32
SharedKeySize = 32
SeedSize = 32 + 32
)
// A DecapsulationKey is the secret key used to decapsulate a shared key from a
// ciphertext. It includes various precomputed values.
type DecapsulationKey struct {
dk [DecapsulationKeySize]byte
encryptionKey
decryptionKey
}
// Bytes returns the extended encoding of the decapsulation key, according to
// FIPS 203 (DRAFT).
func (dk *DecapsulationKey) Bytes() []byte {
var b [DecapsulationKeySize]byte
copy(b[:], dk.dk[:])
return b[:]
}
// EncapsulationKey returns the public encapsulation key necessary to produce
// ciphertexts.
func (dk *DecapsulationKey) EncapsulationKey() []byte {
var b [EncapsulationKeySize]byte
copy(b[:], dk.dk[decryptionKeySize:])
return b[:]
}
// encryptionKey is the parsed and expanded form of a PKE encryption key.
type encryptionKey struct {
t [k]nttElement // ByteDecode₁₂(ek[:384k])
A [k * k]nttElement // A[i*k+j] = sampleNTT(ρ, j, i)
}
// decryptionKey is the parsed and expanded form of a PKE decryption key.
type decryptionKey struct {
s [k]nttElement // ByteDecode₁₂(dk[:decryptionKeySize])
}
// GenerateKey generates a new decapsulation key, drawing random bytes from
// crypto/rand. The decapsulation key must be kept secret.
func GenerateKey() (*DecapsulationKey, error) {
// The actual logic is in a separate function to outline this allocation.
dk := &DecapsulationKey{}
return generateKey(dk)
}
func generateKey(dk *DecapsulationKey) (*DecapsulationKey, error) {
var d [32]byte
if _, err := rand.Read(d[:]); err != nil {
return nil, errors.New("mlkem768: crypto/rand Read failed: " + err.Error())
}
var z [32]byte
if _, err := rand.Read(z[:]); err != nil {
return nil, errors.New("mlkem768: crypto/rand Read failed: " + err.Error())
}
return kemKeyGen(dk, &d, &z), nil
}
// NewKeyFromSeed deterministically generates a decapsulation key from a 64-byte
// seed in the "d || z" form. The seed must be uniformly random.
func NewKeyFromSeed(seed []byte) (*DecapsulationKey, error) {
// The actual logic is in a separate function to outline this allocation.
dk := &DecapsulationKey{}
return newKeyFromSeed(dk, seed)
}
func newKeyFromSeed(dk *DecapsulationKey, seed []byte) (*DecapsulationKey, error) {
if len(seed) != SeedSize {
return nil, errors.New("mlkem768: invalid seed length")
}
d := (*[32]byte)(seed[:32])
z := (*[32]byte)(seed[32:])
return kemKeyGen(dk, d, z), nil
}
// NewKeyFromExtendedEncoding parses a decapsulation key from its FIPS 203
// (DRAFT) extended encoding.
func NewKeyFromExtendedEncoding(decapsulationKey []byte) (*DecapsulationKey, error) {
// The actual logic is in a separate function to outline this allocation.
dk := &DecapsulationKey{}
return newKeyFromExtendedEncoding(dk, decapsulationKey)
}
func newKeyFromExtendedEncoding(dk *DecapsulationKey, dkBytes []byte) (*DecapsulationKey, error) {
if len(dkBytes) != DecapsulationKeySize {
return nil, errors.New("mlkem768: invalid decapsulation key length")
}
// Note that we don't check that H(ek) matches ekPKE, as that's not
// specified in FIPS 203 (DRAFT). This is one reason to prefer the seed
// private key format.
dk.dk = [DecapsulationKeySize]byte(dkBytes)
dkPKE := dkBytes[:decryptionKeySize]
if err := parseDK(&dk.decryptionKey, dkPKE); err != nil {
return nil, err
}
ekPKE := dkBytes[decryptionKeySize : decryptionKeySize+encryptionKeySize]
if err := parseEK(&dk.encryptionKey, ekPKE); err != nil {
return nil, err
}
return dk, nil
}
// kemKeyGen generates a decapsulation key.
//
// It implements ML-KEM.KeyGen according to FIPS 203 (DRAFT), Algorithm 15, and
// K-PKE.KeyGen according to FIPS 203 (DRAFT), Algorithm 12. The two are merged
// to save copies and allocations.
func kemKeyGen(dk *DecapsulationKey, d, z *[32]byte) *DecapsulationKey {
if dk == nil {
dk = &DecapsulationKey{}
}
G := sha3.Sum512(d[:])
ρ, σ := G[:32], G[32:]
A := &dk.A
for i := byte(0); i < k; i++ {
for j := byte(0); j < k; j++ {
// Note that this is consistent with Kyber round 3, rather than with
// the initial draft of FIPS 203, because NIST signaled that the
// change was involuntary and will be reverted.
A[i*k+j] = sampleNTT(ρ, j, i)
}
}
var N byte
s := &dk.s
for i := range s {
s[i] = ntt(samplePolyCBD(σ, N))
N++
}
e := make([]nttElement, k)
for i := range e {
e[i] = ntt(samplePolyCBD(σ, N))
N++
}
t := &dk.t
for i := range t { // t = A ◦ s + e
t[i] = e[i]
for j := range s {
t[i] = polyAdd(t[i], nttMul(A[i*k+j], s[j]))
}
}
// dkPKE ← ByteEncode₁₂(s)
// ekPKE ← ByteEncode₁₂(t) || ρ
// ek ← ekPKE
// dk ← dkPKE || ek || H(ek) || z
dkB := dk.dk[:0]
for i := range s {
dkB = polyByteEncode(dkB, s[i])
}
for i := range t {
dkB = polyByteEncode(dkB, t[i])
}
dkB = append(dkB, ρ...)
H := sha3.New256()
H.Write(dkB[decryptionKeySize:])
dkB = H.Sum(dkB)
dkB = append(dkB, z[:]...)
if len(dkB) != len(dk.dk) {
panic("mlkem768: internal error: invalid decapsulation key size")
}
return dk
}
// Encapsulate generates a shared key and an associated ciphertext from an
// encapsulation key, drawing random bytes from crypto/rand.
// If the encapsulation key is not valid, Encapsulate returns an error.
//
// The shared key must be kept secret.
func Encapsulate(encapsulationKey []byte) (ciphertext, sharedKey []byte, err error) {
// The actual logic is in a separate function to outline this allocation.
var cc [CiphertextSize]byte
return encapsulate(&cc, encapsulationKey)
}
func encapsulate(cc *[CiphertextSize]byte, encapsulationKey []byte) (ciphertext, sharedKey []byte, err error) {
if len(encapsulationKey) != EncapsulationKeySize {
return nil, nil, errors.New("mlkem768: invalid encapsulation key length")
}
var m [messageSize]byte
if _, err := rand.Read(m[:]); err != nil {
return nil, nil, errors.New("mlkem768: crypto/rand Read failed: " + err.Error())
}
return kemEncaps(cc, encapsulationKey, &m)
}
// kemEncaps generates a shared key and an associated ciphertext.
//
// It implements ML-KEM.Encaps according to FIPS 203 (DRAFT), Algorithm 16.
func kemEncaps(cc *[CiphertextSize]byte, ek []byte, m *[messageSize]byte) (c, K []byte, err error) {
if cc == nil {
cc = &[CiphertextSize]byte{}
}
H := sha3.Sum256(ek[:])
g := sha3.New512()
g.Write(m[:])
g.Write(H[:])
G := g.Sum(nil)
K, r := G[:SharedKeySize], G[SharedKeySize:]
var ex encryptionKey
if err := parseEK(&ex, ek[:]); err != nil {
return nil, nil, err
}
c = pkeEncrypt(cc, &ex, m, r)
return c, K, nil
}
// parseEK parses an encryption key from its encoded form.
//
// It implements the initial stages of K-PKE.Encrypt according to FIPS 203
// (DRAFT), Algorithm 13.
func parseEK(ex *encryptionKey, ekPKE []byte) error {
if len(ekPKE) != encryptionKeySize {
return errors.New("mlkem768: invalid encryption key length")
}
for i := range ex.t {
var err error
ex.t[i], err = polyByteDecode[nttElement](ekPKE[:encodingSize12])
if err != nil {
return err
}
ekPKE = ekPKE[encodingSize12:]
}
ρ := ekPKE
for i := byte(0); i < k; i++ {
for j := byte(0); j < k; j++ {
// See the note in pkeKeyGen about the order of the indices being
// consistent with Kyber round 3.
ex.A[i*k+j] = sampleNTT(ρ, j, i)
}
}
return nil
}
// pkeEncrypt encrypt a plaintext message.
//
// It implements K-PKE.Encrypt according to FIPS 203 (DRAFT), Algorithm 13,
// although the computation of t and AT is done in parseEK.
func pkeEncrypt(cc *[CiphertextSize]byte, ex *encryptionKey, m *[messageSize]byte, rnd []byte) []byte {
var N byte
r, e1 := make([]nttElement, k), make([]ringElement, k)
for i := range r {
r[i] = ntt(samplePolyCBD(rnd, N))
N++
}
for i := range e1 {
e1[i] = samplePolyCBD(rnd, N)
N++
}
e2 := samplePolyCBD(rnd, N)
u := make([]ringElement, k) // NTT⁻¹(AT ◦ r) + e1
for i := range u {
u[i] = e1[i]
for j := range r {
// Note that i and j are inverted, as we need the transposed of A.
u[i] = polyAdd(u[i], inverseNTT(nttMul(ex.A[j*k+i], r[j])))
}
}
μ := ringDecodeAndDecompress1(m)
var vNTT nttElement // t⊺ ◦ r
for i := range ex.t {
vNTT = polyAdd(vNTT, nttMul(ex.t[i], r[i]))
}
v := polyAdd(polyAdd(inverseNTT(vNTT), e2), μ)
c := cc[:0]
for _, f := range u {
c = ringCompressAndEncode10(c, f)
}
c = ringCompressAndEncode4(c, v)
return c
}
// Decapsulate generates a shared key from a ciphertext and a decapsulation key.
// If the ciphertext is not valid, Decapsulate returns an error.
//
// The shared key must be kept secret.
func Decapsulate(dk *DecapsulationKey, ciphertext []byte) (sharedKey []byte, err error) {
if len(ciphertext) != CiphertextSize {
return nil, errors.New("mlkem768: invalid ciphertext length")
}
c := (*[CiphertextSize]byte)(ciphertext)
return kemDecaps(dk, c), nil
}
// kemDecaps produces a shared key from a ciphertext.
//
// It implements ML-KEM.Decaps according to FIPS 203 (DRAFT), Algorithm 17.
func kemDecaps(dk *DecapsulationKey, c *[CiphertextSize]byte) (K []byte) {
h := dk.dk[decryptionKeySize+encryptionKeySize : decryptionKeySize+encryptionKeySize+32]
z := dk.dk[decryptionKeySize+encryptionKeySize+32:]
m := pkeDecrypt(&dk.decryptionKey, c)
g := sha3.New512()
g.Write(m[:])
g.Write(h)
G := g.Sum(nil)
Kprime, r := G[:SharedKeySize], G[SharedKeySize:]
J := sha3.NewShake256()
J.Write(z)
J.Write(c[:])
Kout := make([]byte, SharedKeySize)
J.Read(Kout)
var cc [CiphertextSize]byte
c1 := pkeEncrypt(&cc, &dk.encryptionKey, (*[32]byte)(m), r)
subtle.ConstantTimeCopy(subtle.ConstantTimeCompare(c[:], c1), Kout, Kprime)
return Kout
}
// parseDK parses a decryption key from its encoded form.
//
// It implements the computation of s from K-PKE.Decrypt according to FIPS 203
// (DRAFT), Algorithm 14.
func parseDK(dx *decryptionKey, dkPKE []byte) error {
if len(dkPKE) != decryptionKeySize {
return errors.New("mlkem768: invalid decryption key length")
}
for i := range dx.s {
f, err := polyByteDecode[nttElement](dkPKE[:encodingSize12])
if err != nil {
return err
}
dx.s[i] = f
dkPKE = dkPKE[encodingSize12:]
}
return nil
}
// pkeDecrypt decrypts a ciphertext.
//
// It implements K-PKE.Decrypt according to FIPS 203 (DRAFT), Algorithm 14,
// although the computation of s is done in parseDK.
func pkeDecrypt(dx *decryptionKey, c *[CiphertextSize]byte) []byte {
u := make([]ringElement, k)
for i := range u {
b := (*[encodingSize10]byte)(c[encodingSize10*i : encodingSize10*(i+1)])
u[i] = ringDecodeAndDecompress10(b)
}
b := (*[encodingSize4]byte)(c[encodingSize10*k:])
v := ringDecodeAndDecompress4(b)
var mask nttElement // s⊺ ◦ NTT(u)
for i := range dx.s {
mask = polyAdd(mask, nttMul(dx.s[i], ntt(u[i])))
}
w := polySub(v, inverseNTT(mask))
return ringCompressAndEncode1(nil, w)
}
// fieldElement is an integer modulo q, an element of ℤ_q. It is always reduced.
type fieldElement uint16
// fieldCheckReduced checks that a value a is < q.
func fieldCheckReduced(a uint16) (fieldElement, error) {
if a >= q {
return 0, errors.New("unreduced field element")
}
return fieldElement(a), nil
}
// fieldReduceOnce reduces a value a < 2q.
func fieldReduceOnce(a uint16) fieldElement {
x := a - q
// If x underflowed, then x >= 2¹⁶ - q > 2¹⁵, so the top bit is set.
x += (x >> 15) * q
return fieldElement(x)
}
func fieldAdd(a, b fieldElement) fieldElement {
x := uint16(a + b)
return fieldReduceOnce(x)
}
func fieldSub(a, b fieldElement) fieldElement {
x := uint16(a - b + q)
return fieldReduceOnce(x)
}
const (
barrettMultiplier = 5039 // 2¹² * 2¹² / q
barrettShift = 24 // log₂(2¹² * 2¹²)
)
// fieldReduce reduces a value a < 2q² using Barrett reduction, to avoid
// potentially variable-time division.
func fieldReduce(a uint32) fieldElement {
quotient := uint32((uint64(a) * barrettMultiplier) >> barrettShift)
return fieldReduceOnce(uint16(a - quotient*q))
}
func fieldMul(a, b fieldElement) fieldElement {
x := uint32(a) * uint32(b)
return fieldReduce(x)
}
// fieldMulSub returns a * (b - c). This operation is fused to save a
// fieldReduceOnce after the subtraction.
func fieldMulSub(a, b, c fieldElement) fieldElement {
x := uint32(a) * uint32(b-c+q)
return fieldReduce(x)
}
// fieldAddMul returns a * b + c * d. This operation is fused to save a
// fieldReduceOnce and a fieldReduce.
func fieldAddMul(a, b, c, d fieldElement) fieldElement {
x := uint32(a) * uint32(b)
x += uint32(c) * uint32(d)
return fieldReduce(x)
}
// compress maps a field element uniformly to the range 0 to 2ᵈ-1, according to
// FIPS 203 (DRAFT), Definition 4.5.
func compress(x fieldElement, d uint8) uint16 {
// We want to compute (x * 2ᵈ) / q, rounded to nearest integer, with 1/2
// rounding up (see FIPS 203 (DRAFT), Section 2.3).
// Barrett reduction produces a quotient and a remainder in the range [0, 2q),
// such that dividend = quotient * q + remainder.
dividend := uint32(x) << d // x * 2ᵈ
quotient := uint32(uint64(dividend) * barrettMultiplier >> barrettShift)
remainder := dividend - quotient*q
// Since the remainder is in the range [0, 2q), not [0, q), we need to
// portion it into three spans for rounding.
//
// [ 0, q/2 ) -> round to 0
// [ q/2, q + q/2 ) -> round to 1
// [ q + q/2, 2q ) -> round to 2
//
// We can convert that to the following logic: add 1 if remainder > q/2,
// then add 1 again if remainder > q + q/2.
//
// Note that if remainder > x, then ⌊x⌋ - remainder underflows, and the top
// bit of the difference will be set.
quotient += (q/2 - remainder) >> 31 & 1
quotient += (q + q/2 - remainder) >> 31 & 1
// quotient might have overflowed at this point, so reduce it by masking.
var mask uint32 = (1 << d) - 1
return uint16(quotient & mask)
}
// decompress maps a number x between 0 and 2ᵈ-1 uniformly to the full range of
// field elements, according to FIPS 203 (DRAFT), Definition 4.6.
func decompress(y uint16, d uint8) fieldElement {
// We want to compute (y * q) / 2ᵈ, rounded to nearest integer, with 1/2
// rounding up (see FIPS 203 (DRAFT), Section 2.3).
dividend := uint32(y) * q
quotient := dividend >> d // (y * q) / 2ᵈ
// The d'th least-significant bit of the dividend (the most significant bit
// of the remainder) is 1 for the top half of the values that divide to the
// same quotient, which are the ones that round up.
quotient += dividend >> (d - 1) & 1
// quotient is at most (2¹¹-1) * q / 2¹¹ + 1 = 3328, so it didn't overflow.
return fieldElement(quotient)
}
// ringElement is a polynomial, an element of R_q, represented as an array
// according to FIPS 203 (DRAFT), Section 2.4.
type ringElement [n]fieldElement
// polyAdd adds two ringElements or nttElements.
func polyAdd[T ~[n]fieldElement](a, b T) (s T) {
for i := range s {
s[i] = fieldAdd(a[i], b[i])
}
return s
}
// polySub subtracts two ringElements or nttElements.
func polySub[T ~[n]fieldElement](a, b T) (s T) {
for i := range s {
s[i] = fieldSub(a[i], b[i])
}
return s
}
// polyByteEncode appends the 384-byte encoding of f to b.
//
// It implements ByteEncode₁₂, according to FIPS 203 (DRAFT), Algorithm 4.
func polyByteEncode[T ~[n]fieldElement](b []byte, f T) []byte {
out, B := sliceForAppend(b, encodingSize12)
for i := 0; i < n; i += 2 {
x := uint32(f[i]) | uint32(f[i+1])<<12
B[0] = uint8(x)
B[1] = uint8(x >> 8)
B[2] = uint8(x >> 16)
B = B[3:]
}
return out
}
// polyByteDecode decodes the 384-byte encoding of a polynomial, checking that
// all the coefficients are properly reduced. This achieves the "Modulus check"
// step of ML-KEM Encapsulation Input Validation.
//
// polyByteDecode is also used in ML-KEM Decapsulation, where the input
// validation is not required, but implicitly allowed by the specification.
//
// It implements ByteDecode₁₂, according to FIPS 203 (DRAFT), Algorithm 5.
func polyByteDecode[T ~[n]fieldElement](b []byte) (T, error) {
if len(b) != encodingSize12 {
return T{}, errors.New("mlkem768: invalid encoding length")
}
var f T
for i := 0; i < n; i += 2 {
d := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16
const mask12 = 0b1111_1111_1111
var err error
if f[i], err = fieldCheckReduced(uint16(d & mask12)); err != nil {
return T{}, errors.New("mlkem768: invalid polynomial encoding")
}
if f[i+1], err = fieldCheckReduced(uint16(d >> 12)); err != nil {
return T{}, errors.New("mlkem768: invalid polynomial encoding")
}
b = b[3:]
}
return f, nil
}
// sliceForAppend takes a slice and a requested number of bytes. It returns a
// slice with the contents of the given slice followed by that many bytes and a
// second slice that aliases into it and contains only the extra bytes. If the
// original slice has sufficient capacity then no allocation is performed.
func sliceForAppend(in []byte, n int) (head, tail []byte) {
if total := len(in) + n; cap(in) >= total {
head = in[:total]
} else {
head = make([]byte, total)
copy(head, in)
}
tail = head[len(in):]
return
}
// ringCompressAndEncode1 appends a 32-byte encoding of a ring element to s,
// compressing one coefficients per bit.
//
// It implements Compress₁, according to FIPS 203 (DRAFT), Definition 4.5,
// followed by ByteEncode₁, according to FIPS 203 (DRAFT), Algorithm 4.
func ringCompressAndEncode1(s []byte, f ringElement) []byte {
s, b := sliceForAppend(s, encodingSize1)
for i := range b {
b[i] = 0
}
for i := range f {
b[i/8] |= uint8(compress(f[i], 1) << (i % 8))
}
return s
}
// ringDecodeAndDecompress1 decodes a 32-byte slice to a ring element where each
// bit is mapped to 0 or ⌈q/2⌋.
//
// It implements ByteDecode₁, according to FIPS 203 (DRAFT), Algorithm 5,
// followed by Decompress₁, according to FIPS 203 (DRAFT), Definition 4.6.
func ringDecodeAndDecompress1(b *[encodingSize1]byte) ringElement {
var f ringElement
for i := range f {
b_i := b[i/8] >> (i % 8) & 1
const halfQ = (q + 1) / 2 // ⌈q/2⌋, rounded up per FIPS 203 (DRAFT), Section 2.3
f[i] = fieldElement(b_i) * halfQ // 0 decompresses to 0, and 1 to ⌈q/2⌋
}
return f
}
// ringCompressAndEncode4 appends a 128-byte encoding of a ring element to s,
// compressing two coefficients per byte.
//
// It implements Compress₄, according to FIPS 203 (DRAFT), Definition 4.5,
// followed by ByteEncode₄, according to FIPS 203 (DRAFT), Algorithm 4.
func ringCompressAndEncode4(s []byte, f ringElement) []byte {
s, b := sliceForAppend(s, encodingSize4)
for i := 0; i < n; i += 2 {
b[i/2] = uint8(compress(f[i], 4) | compress(f[i+1], 4)<<4)
}
return s
}
// ringDecodeAndDecompress4 decodes a 128-byte encoding of a ring element where
// each four bits are mapped to an equidistant distribution.
//
// It implements ByteDecode₄, according to FIPS 203 (DRAFT), Algorithm 5,
// followed by Decompress₄, according to FIPS 203 (DRAFT), Definition 4.6.
func ringDecodeAndDecompress4(b *[encodingSize4]byte) ringElement {
var f ringElement
for i := 0; i < n; i += 2 {
f[i] = fieldElement(decompress(uint16(b[i/2]&0b1111), 4))
f[i+1] = fieldElement(decompress(uint16(b[i/2]>>4), 4))
}
return f
}
// ringCompressAndEncode10 appends a 320-byte encoding of a ring element to s,
// compressing four coefficients per five bytes.
//
// It implements Compress₁₀, according to FIPS 203 (DRAFT), Definition 4.5,
// followed by ByteEncode₁₀, according to FIPS 203 (DRAFT), Algorithm 4.
func ringCompressAndEncode10(s []byte, f ringElement) []byte {
s, b := sliceForAppend(s, encodingSize10)
for i := 0; i < n; i += 4 {
var x uint64
x |= uint64(compress(f[i+0], 10))
x |= uint64(compress(f[i+1], 10)) << 10
x |= uint64(compress(f[i+2], 10)) << 20
x |= uint64(compress(f[i+3], 10)) << 30
b[0] = uint8(x)
b[1] = uint8(x >> 8)
b[2] = uint8(x >> 16)
b[3] = uint8(x >> 24)
b[4] = uint8(x >> 32)
b = b[5:]
}
return s
}
// ringDecodeAndDecompress10 decodes a 320-byte encoding of a ring element where
// each ten bits are mapped to an equidistant distribution.
//
// It implements ByteDecode₁₀, according to FIPS 203 (DRAFT), Algorithm 5,
// followed by Decompress₁₀, according to FIPS 203 (DRAFT), Definition 4.6.
func ringDecodeAndDecompress10(bb *[encodingSize10]byte) ringElement {
b := bb[:]
var f ringElement
for i := 0; i < n; i += 4 {
x := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32
b = b[5:]
f[i] = fieldElement(decompress(uint16(x>>0&0b11_1111_1111), 10))
f[i+1] = fieldElement(decompress(uint16(x>>10&0b11_1111_1111), 10))
f[i+2] = fieldElement(decompress(uint16(x>>20&0b11_1111_1111), 10))
f[i+3] = fieldElement(decompress(uint16(x>>30&0b11_1111_1111), 10))
}
return f
}
// samplePolyCBD draws a ringElement from the special Dη distribution given a
// stream of random bytes generated by the PRF function, according to FIPS 203
// (DRAFT), Algorithm 7 and Definition 4.1.
func samplePolyCBD(s []byte, b byte) ringElement {
prf := sha3.NewShake256()
prf.Write(s)
prf.Write([]byte{b})
B := make([]byte, 128)
prf.Read(B)
// SamplePolyCBD simply draws four (2η) bits for each coefficient, and adds
// the first two and subtracts the last two.
var f ringElement
for i := 0; i < n; i += 2 {
b := B[i/2]
b_7, b_6, b_5, b_4 := b>>7, b>>6&1, b>>5&1, b>>4&1
b_3, b_2, b_1, b_0 := b>>3&1, b>>2&1, b>>1&1, b&1
f[i] = fieldSub(fieldElement(b_0+b_1), fieldElement(b_2+b_3))
f[i+1] = fieldSub(fieldElement(b_4+b_5), fieldElement(b_6+b_7))
}
return f
}
// nttElement is an NTT representation, an element of T_q, represented as an
// array according to FIPS 203 (DRAFT), Section 2.4.
type nttElement [n]fieldElement
// gammas are the values ζ^2BitRev7(i)+1 mod q for each index i.
var gammas = [128]fieldElement{17, 3312, 2761, 568, 583, 2746, 2649, 680, 1637, 1692, 723, 2606, 2288, 1041, 1100, 2229, 1409, 1920, 2662, 667, 3281, 48, 233, 3096, 756, 2573, 2156, 1173, 3015, 314, 3050, 279, 1703, 1626, 1651, 1678, 2789, 540, 1789, 1540, 1847, 1482, 952, 2377, 1461, 1868, 2687, 642, 939, 2390, 2308, 1021, 2437, 892, 2388, 941, 733, 2596, 2337, 992, 268, 3061, 641, 2688, 1584, 1745, 2298, 1031, 2037, 1292, 3220, 109, 375, 2954, 2549, 780, 2090, 1239, 1645, 1684, 1063, 2266, 319, 3010, 2773, 556, 757, 2572, 2099, 1230, 561, 2768, 2466, 863, 2594, 735, 2804, 525, 1092, 2237, 403, 2926, 1026, 2303, 1143, 2186, 2150, 1179, 2775, 554, 886, 2443, 1722, 1607, 1212, 2117, 1874, 1455, 1029, 2300, 2110, 1219, 2935, 394, 885, 2444, 2154, 1175}
// nttMul multiplies two nttElements.
//
// It implements MultiplyNTTs, according to FIPS 203 (DRAFT), Algorithm 10.
func nttMul(f, g nttElement) nttElement {
var h nttElement
// We use i += 2 for bounds check elimination. See https://go.dev/issue/66826.
for i := 0; i < 256; i += 2 {
a0, a1 := f[i], f[i+1]
b0, b1 := g[i], g[i+1]
h[i] = fieldAddMul(a0, b0, fieldMul(a1, b1), gammas[i/2])
h[i+1] = fieldAddMul(a0, b1, a1, b0)
}
return h
}
// zetas are the values ζ^BitRev7(k) mod q for each index k.
var zetas = [128]fieldElement{1, 1729, 2580, 3289, 2642, 630, 1897, 848, 1062, 1919, 193, 797, 2786, 3260, 569, 1746, 296, 2447, 1339, 1476, 3046, 56, 2240, 1333, 1426, 2094, 535, 2882, 2393, 2879, 1974, 821, 289, 331, 3253, 1756, 1197, 2304, 2277, 2055, 650, 1977, 2513, 632, 2865, 33, 1320, 1915, 2319, 1435, 807, 452, 1438, 2868, 1534, 2402, 2647, 2617, 1481, 648, 2474, 3110, 1227, 910, 17, 2761, 583, 2649, 1637, 723, 2288, 1100, 1409, 2662, 3281, 233, 756, 2156, 3015, 3050, 1703, 1651, 2789, 1789, 1847, 952, 1461, 2687, 939, 2308, 2437, 2388, 733, 2337, 268, 641, 1584, 2298, 2037, 3220, 375, 2549, 2090, 1645, 1063, 319, 2773, 757, 2099, 561, 2466, 2594, 2804, 1092, 403, 1026, 1143, 2150, 2775, 886, 1722, 1212, 1874, 1029, 2110, 2935, 885, 2154}
// ntt maps a ringElement to its nttElement representation.
//
// It implements NTT, according to FIPS 203 (DRAFT), Algorithm 8.
func ntt(f ringElement) nttElement {
k := 1
for len := 128; len >= 2; len /= 2 {
for start := 0; start < 256; start += 2 * len {
zeta := zetas[k]
k++
// Bounds check elimination hint.
f, flen := f[start:start+len], f[start+len:start+len+len]
for j := 0; j < len; j++ {
t := fieldMul(zeta, flen[j])
flen[j] = fieldSub(f[j], t)
f[j] = fieldAdd(f[j], t)
}
}
}
return nttElement(f)
}
// inverseNTT maps a nttElement back to the ringElement it represents.
//
// It implements NTT⁻¹, according to FIPS 203 (DRAFT), Algorithm 9.
func inverseNTT(f nttElement) ringElement {
k := 127
for len := 2; len <= 128; len *= 2 {
for start := 0; start < 256; start += 2 * len {
zeta := zetas[k]
k--
// Bounds check elimination hint.
f, flen := f[start:start+len], f[start+len:start+len+len]
for j := 0; j < len; j++ {
t := f[j]
f[j] = fieldAdd(t, flen[j])
flen[j] = fieldMulSub(zeta, flen[j], t)
}
}
}
for i := range f {
f[i] = fieldMul(f[i], 3303) // 3303 = 128⁻¹ mod q
}
return ringElement(f)
}
// sampleNTT draws a uniformly random nttElement from a stream of uniformly
// random bytes generated by the XOF function, according to FIPS 203 (DRAFT),
// Algorithm 6 and Definition 4.2.
func sampleNTT(rho []byte, ii, jj byte) nttElement {
B := sha3.NewShake128()
B.Write(rho)
B.Write([]byte{ii, jj})
// SampleNTT essentially draws 12 bits at a time from r, interprets them in
// little-endian, and rejects values higher than q, until it drew 256
// values. (The rejection rate is approximately 19%.)
//
// To do this from a bytes stream, it draws three bytes at a time, and
// splits them into two uint16 appropriately masked.
//
// r₀ r₁ r₂
// |- - - - - - - -|- - - - - - - -|- - - - - - - -|
//
// Uint16(r₀ || r₁)
// |- - - - - - - - - - - - - - - -|
// |- - - - - - - - - - - -|
// d₁
//
// Uint16(r₁ || r₂)
// |- - - - - - - - - - - - - - - -|
// |- - - - - - - - - - - -|
// d₂
//
// Note that in little-endian, the rightmost bits are the most significant
// bits (dropped with a mask) and the leftmost bits are the least
// significant bits (dropped with a right shift).
var a nttElement
var j int // index into a
var buf [24]byte // buffered reads from B
off := len(buf) // index into buf, starts in a "buffer fully consumed" state
for {
if off >= len(buf) {
B.Read(buf[:])
off = 0
}
d1 := byteorder.LeUint16(buf[off:]) & 0b1111_1111_1111
d2 := byteorder.LeUint16(buf[off+1:]) >> 4
off += 3
if d1 < q {
a[j] = fieldElement(d1)
j++
}
if j >= len(a) {
break
}
if d2 < q {
a[j] = fieldElement(d2)
j++
}
if j >= len(a) {
break
}
}
return a
}

View file

@ -1,467 +0,0 @@
// Copyright 2023 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 mlkem768
import (
"bytes"
"crypto/rand"
_ "embed"
"encoding/hex"
"errors"
"flag"
"math/big"
"strconv"
"testing"
"golang.org/x/crypto/sha3"
)
func TestFieldReduce(t *testing.T) {
for a := uint32(0); a < 2*q*q; a++ {
got := fieldReduce(a)
exp := fieldElement(a % q)
if got != exp {
t.Fatalf("reduce(%d) = %d, expected %d", a, got, exp)
}
}
}
func TestFieldAdd(t *testing.T) {
for a := fieldElement(0); a < q; a++ {
for b := fieldElement(0); b < q; b++ {
got := fieldAdd(a, b)
exp := (a + b) % q
if got != exp {
t.Fatalf("%d + %d = %d, expected %d", a, b, got, exp)
}
}
}
}
func TestFieldSub(t *testing.T) {
for a := fieldElement(0); a < q; a++ {
for b := fieldElement(0); b < q; b++ {
got := fieldSub(a, b)
exp := (a - b + q) % q
if got != exp {
t.Fatalf("%d - %d = %d, expected %d", a, b, got, exp)
}
}
}
}
func TestFieldMul(t *testing.T) {
for a := fieldElement(0); a < q; a++ {
for b := fieldElement(0); b < q; b++ {
got := fieldMul(a, b)
exp := fieldElement((uint32(a) * uint32(b)) % q)
if got != exp {
t.Fatalf("%d * %d = %d, expected %d", a, b, got, exp)
}
}
}
}
func TestDecompressCompress(t *testing.T) {
for _, bits := range []uint8{1, 4, 10} {
for a := uint16(0); a < 1<<bits; a++ {
f := decompress(a, bits)
if f >= q {
t.Fatalf("decompress(%d, %d) = %d >= q", a, bits, f)
}
got := compress(f, bits)
if got != a {
t.Fatalf("compress(decompress(%d, %d), %d) = %d", a, bits, bits, got)
}
}
for a := fieldElement(0); a < q; a++ {
c := compress(a, bits)
if c >= 1<<bits {
t.Fatalf("compress(%d, %d) = %d >= 2^bits", a, bits, c)
}
got := decompress(c, bits)
diff := min(a-got, got-a, a-got+q, got-a+q)
ceil := q / (1 << bits)
if diff > fieldElement(ceil) {
t.Fatalf("decompress(compress(%d, %d), %d) = %d (diff %d, max diff %d)",
a, bits, bits, got, diff, ceil)
}
}
}
}
func CompressRat(x fieldElement, d uint8) uint16 {
if x >= q {
panic("x out of range")
}
if d <= 0 || d >= 12 {
panic("d out of range")
}
precise := big.NewRat((1<<d)*int64(x), q) // (2ᵈ / q) * x == (2ᵈ * x) / q
// FloatString rounds halves away from 0, and our result should always be positive,
// so it should work as we expect. (There's no direct way to round a Rat.)
rounded, err := strconv.ParseInt(precise.FloatString(0), 10, 64)
if err != nil {
panic(err)
}
// If we rounded up, `rounded` may be equal to 2ᵈ, so we perform a final reduction.
return uint16(rounded % (1 << d))
}
func TestCompress(t *testing.T) {
for d := 1; d < 12; d++ {
for n := 0; n < q; n++ {
expected := CompressRat(fieldElement(n), uint8(d))
result := compress(fieldElement(n), uint8(d))
if result != expected {
t.Errorf("compress(%d, %d): got %d, expected %d", n, d, result, expected)
}
}
}
}
func DecompressRat(y uint16, d uint8) fieldElement {
if y >= 1<<d {
panic("y out of range")
}
if d <= 0 || d >= 12 {
panic("d out of range")
}
precise := big.NewRat(q*int64(y), 1<<d) // (q / 2ᵈ) * y == (q * y) / 2ᵈ
// FloatString rounds halves away from 0, and our result should always be positive,
// so it should work as we expect. (There's no direct way to round a Rat.)
rounded, err := strconv.ParseInt(precise.FloatString(0), 10, 64)
if err != nil {
panic(err)
}
// If we rounded up, `rounded` may be equal to q, so we perform a final reduction.
return fieldElement(rounded % q)
}
func TestDecompress(t *testing.T) {
for d := 1; d < 12; d++ {
for n := 0; n < (1 << d); n++ {
expected := DecompressRat(uint16(n), uint8(d))
result := decompress(uint16(n), uint8(d))
if result != expected {
t.Errorf("decompress(%d, %d): got %d, expected %d", n, d, result, expected)
}
}
}
}
func BitRev7(n uint8) uint8 {
if n>>7 != 0 {
panic("not 7 bits")
}
var r uint8
r |= n >> 6 & 0b0000_0001
r |= n >> 4 & 0b0000_0010
r |= n >> 2 & 0b0000_0100
r |= n /**/ & 0b0000_1000
r |= n << 2 & 0b0001_0000
r |= n << 4 & 0b0010_0000
r |= n << 6 & 0b0100_0000
return r
}
func TestZetas(t *testing.T) {
ζ := big.NewInt(17)
q := big.NewInt(q)
for k, zeta := range zetas {
// ζ^BitRev7(k) mod q
exp := new(big.Int).Exp(ζ, big.NewInt(int64(BitRev7(uint8(k)))), q)
if big.NewInt(int64(zeta)).Cmp(exp) != 0 {
t.Errorf("zetas[%d] = %v, expected %v", k, zeta, exp)
}
}
}
func TestGammas(t *testing.T) {
ζ := big.NewInt(17)
q := big.NewInt(q)
for k, gamma := range gammas {
// ζ^2BitRev7(i)+1
exp := new(big.Int).Exp(ζ, big.NewInt(int64(BitRev7(uint8(k)))*2+1), q)
if big.NewInt(int64(gamma)).Cmp(exp) != 0 {
t.Errorf("gammas[%d] = %v, expected %v", k, gamma, exp)
}
}
}
func TestRoundTrip(t *testing.T) {
dk, err := GenerateKey()
if err != nil {
t.Fatal(err)
}
c, Ke, err := Encapsulate(dk.EncapsulationKey())
if err != nil {
t.Fatal(err)
}
Kd, err := Decapsulate(dk, c)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(Ke, Kd) {
t.Fail()
}
dk1, err := GenerateKey()
if err != nil {
t.Fatal(err)
}
if bytes.Equal(dk.EncapsulationKey(), dk1.EncapsulationKey()) {
t.Fail()
}
if bytes.Equal(dk.Bytes(), dk1.Bytes()) {
t.Fail()
}
if bytes.Equal(dk.Bytes()[EncapsulationKeySize-32:], dk1.Bytes()[EncapsulationKeySize-32:]) {
t.Fail()
}
c1, Ke1, err := Encapsulate(dk.EncapsulationKey())
if err != nil {
t.Fatal(err)
}
if bytes.Equal(c, c1) {
t.Fail()
}
if bytes.Equal(Ke, Ke1) {
t.Fail()
}
}
func TestBadLengths(t *testing.T) {
dk, err := GenerateKey()
if err != nil {
t.Fatal(err)
}
ek := dk.EncapsulationKey()
for i := 0; i < len(ek)-1; i++ {
if _, _, err := Encapsulate(ek[:i]); err == nil {
t.Errorf("expected error for ek length %d", i)
}
}
ekLong := ek
for i := 0; i < 100; i++ {
ekLong = append(ekLong, 0)
if _, _, err := Encapsulate(ekLong); err == nil {
t.Errorf("expected error for ek length %d", len(ekLong))
}
}
c, _, err := Encapsulate(ek)
if err != nil {
t.Fatal(err)
}
for i := 0; i < len(dk.Bytes())-1; i++ {
if _, err := NewKeyFromExtendedEncoding(dk.Bytes()[:i]); err == nil {
t.Errorf("expected error for dk length %d", i)
}
}
dkLong := dk.Bytes()
for i := 0; i < 100; i++ {
dkLong = append(dkLong, 0)
if _, err := NewKeyFromExtendedEncoding(dkLong); err == nil {
t.Errorf("expected error for dk length %d", len(dkLong))
}
}
for i := 0; i < len(c)-1; i++ {
if _, err := Decapsulate(dk, c[:i]); err == nil {
t.Errorf("expected error for c length %d", i)
}
}
cLong := c
for i := 0; i < 100; i++ {
cLong = append(cLong, 0)
if _, err := Decapsulate(dk, cLong); err == nil {
t.Errorf("expected error for c length %d", len(cLong))
}
}
}
func EncapsulateDerand(ek, m []byte) (c, K []byte, err error) {
if len(m) != messageSize {
return nil, nil, errors.New("bad message length")
}
return kemEncaps(nil, ek, (*[messageSize]byte)(m))
}
func DecapsulateFromBytes(dkBytes []byte, c []byte) ([]byte, error) {
dk, err := NewKeyFromExtendedEncoding(dkBytes)
if err != nil {
return nil, err
}
return Decapsulate(dk, c)
}
func GenerateKeyDerand(t testing.TB, d, z []byte) ([]byte, *DecapsulationKey) {
if len(d) != 32 || len(z) != 32 {
t.Fatal("bad length")
}
dk := kemKeyGen(nil, (*[32]byte)(d), (*[32]byte)(z))
return dk.EncapsulationKey(), dk
}
var millionFlag = flag.Bool("million", false, "run the million vector test")
// TestPQCrystalsAccumulated accumulates the 10k vectors generated by the
// reference implementation and checks the hash of the result, to avoid checking
// in 150MB of test vectors.
func TestPQCrystalsAccumulated(t *testing.T) {
n := 10000
expected := "f7db260e1137a742e05fe0db9525012812b004d29040a5b606aad3d134b548d3"
if testing.Short() {
n = 100
expected = "8d0c478ead6037897a0da6be21e5399545babf5fc6dd10c061c99b7dee2bf0dc"
}
if *millionFlag {
n = 1000000
expected = "70090cc5842aad0ec43d5042c783fae9bc320c047b5dafcb6e134821db02384d"
}
s := sha3.NewShake128()
o := sha3.NewShake128()
d := make([]byte, 32)
z := make([]byte, 32)
msg := make([]byte, 32)
ct1 := make([]byte, CiphertextSize)
for i := 0; i < n; i++ {
s.Read(d)
s.Read(z)
ek, dk := GenerateKeyDerand(t, d, z)
o.Write(ek)
o.Write(dk.Bytes())
s.Read(msg)
ct, k, err := EncapsulateDerand(ek, msg)
if err != nil {
t.Fatal(err)
}
o.Write(ct)
o.Write(k)
kk, err := Decapsulate(dk, ct)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(kk, k) {
t.Errorf("k: got %x, expected %x", kk, k)
}
s.Read(ct1)
k1, err := Decapsulate(dk, ct1)
if err != nil {
t.Fatal(err)
}
o.Write(k1)
}
got := hex.EncodeToString(o.Sum(nil))
if got != expected {
t.Errorf("got %s, expected %s", got, expected)
}
}
var sink byte
func BenchmarkKeyGen(b *testing.B) {
var dk DecapsulationKey
var d, z [32]byte
rand.Read(d[:])
rand.Read(z[:])
b.ResetTimer()
for i := 0; i < b.N; i++ {
dk := kemKeyGen(&dk, &d, &z)
sink ^= dk.EncapsulationKey()[0]
}
}
func BenchmarkEncaps(b *testing.B) {
d := make([]byte, 32)
rand.Read(d)
z := make([]byte, 32)
rand.Read(z)
var m [messageSize]byte
rand.Read(m[:])
ek, _ := GenerateKeyDerand(b, d, z)
var c [CiphertextSize]byte
b.ResetTimer()
for i := 0; i < b.N; i++ {
c, K, err := kemEncaps(&c, ek, &m)
if err != nil {
b.Fatal(err)
}
sink ^= c[0] ^ K[0]
}
}
func BenchmarkDecaps(b *testing.B) {
d := make([]byte, 32)
rand.Read(d)
z := make([]byte, 32)
rand.Read(z)
m := make([]byte, 32)
rand.Read(m)
ek, dk := GenerateKeyDerand(b, d, z)
c, _, err := EncapsulateDerand(ek, m)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
K := kemDecaps(dk, (*[CiphertextSize]byte)(c))
sink ^= K[0]
}
}
func BenchmarkRoundTrip(b *testing.B) {
dk, err := GenerateKey()
if err != nil {
b.Fatal(err)
}
ek := dk.EncapsulationKey()
c, _, err := Encapsulate(ek)
if err != nil {
b.Fatal(err)
}
b.Run("Alice", func(b *testing.B) {
for i := 0; i < b.N; i++ {
dkS, err := GenerateKey()
if err != nil {
b.Fatal(err)
}
ekS := dkS.EncapsulationKey()
sink ^= ekS[0]
Ks, err := Decapsulate(dk, c)
if err != nil {
b.Fatal(err)
}
sink ^= Ks[0]
}
})
b.Run("Bob", func(b *testing.B) {
for i := 0; i < b.N; i++ {
cS, Ks, err := Encapsulate(ek)
if err != nil {
b.Fatal(err)
}
sink ^= cS[0] ^ Ks[0]
}
})
}

69
internal/tls12/tls12.go Normal file
View file

@ -0,0 +1,69 @@
// 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 tls12
import (
"crypto/hmac"
"hash"
)
// PRF implements the TLS 1.2 pseudo-random function, as defined in RFC 5246,
// Section 5 and allowed by SP 800-135, Revision 1, Section 4.2.2.
func PRF(hash func() hash.Hash, secret []byte, label string, seed []byte, keyLen int) []byte {
labelAndSeed := make([]byte, len(label)+len(seed))
copy(labelAndSeed, label)
copy(labelAndSeed[len(label):], seed)
result := make([]byte, keyLen)
pHash(hash, result, secret, labelAndSeed)
return result
}
// pHash implements the P_hash function, as defined in RFC 5246, Section 5.
func pHash(hash func() hash.Hash, result, secret, seed []byte) {
h := hmac.New(hash, secret)
h.Write(seed)
a := h.Sum(nil)
for len(result) > 0 {
h.Reset()
h.Write(a)
h.Write(seed)
b := h.Sum(nil)
n := copy(result, b)
result = result[n:]
h.Reset()
h.Write(a)
a = h.Sum(nil)
}
}
const masterSecretLength = 48
const extendedMasterSecretLabel = "extended master secret"
// MasterSecret implements the TLS 1.2 extended master secret derivation, as
// defined in RFC 7627 and allowed by SP 800-135, Revision 1, Section 4.2.2.
func MasterSecret(hash func() hash.Hash, preMasterSecret, transcript []byte) []byte {
// [uTLS SECTION BEGIN]
// "The TLS 1.2 KDF is an approved KDF when the following conditions are
// satisfied: [...] (3) P_HASH uses either SHA-256, SHA-384 or SHA-512."
// h := hash()
// switch any(h).(type) {
// case *sha256.Digest:
// if h.Size() != 32 {
// fips140.RecordNonApproved()
// }
// case *sha512.Digest:
// if h.Size() != 46 && h.Size() != 64 {
// fips140.RecordNonApproved()
// }
// default:
// fips140.RecordNonApproved()
// }
// [uTLS SECTION END]
return PRF(hash, preMasterSecret, extendedMasterSecretLabel, transcript, masterSecretLength)
}

179
internal/tls13/tls13.go Normal file
View file

@ -0,0 +1,179 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package tls13 implements the TLS 1.3 Key Schedule as specified in RFC 8446,
// Section 7.1 and allowed by FIPS 140-3 IG 2.4.B Resolution 7.
package tls13
import (
fips140 "hash"
"github.com/refraction-networking/utls/internal/byteorder"
"github.com/refraction-networking/utls/internal/hkdf"
)
// We don't set the service indicator in this package but we delegate that to
// the underlying functions because the TLS 1.3 KDF does not have a standard of
// its own.
// ExpandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
func ExpandLabel[H fips140.Hash](hash func() H, secret []byte, label string, context []byte, length int) []byte {
if len("tls13 ")+len(label) > 255 || len(context) > 255 {
// It should be impossible for this to panic: labels are fixed strings,
// and context is either a fixed-length computed hash, or parsed from a
// field which has the same length limitation.
//
// Another reasonable approach might be to return a randomized slice if
// we encounter an error, which would break the connection, but avoid
// panicking. This would perhaps be safer but significantly more
// confusing to users.
panic("tls13: label or context too long")
}
hkdfLabel := make([]byte, 0, 2+1+len("tls13 ")+len(label)+1+len(context))
hkdfLabel = byteorder.BEAppendUint16(hkdfLabel, uint16(length))
hkdfLabel = append(hkdfLabel, byte(len("tls13 ")+len(label)))
hkdfLabel = append(hkdfLabel, "tls13 "...)
hkdfLabel = append(hkdfLabel, label...)
hkdfLabel = append(hkdfLabel, byte(len(context)))
hkdfLabel = append(hkdfLabel, context...)
return hkdf.Expand(hash, secret, string(hkdfLabel), length)
}
func extract[H fips140.Hash](hash func() H, newSecret, currentSecret []byte) []byte {
if newSecret == nil {
newSecret = make([]byte, hash().Size())
}
return hkdf.Extract(hash, newSecret, currentSecret)
}
func deriveSecret[H fips140.Hash](hash func() H, secret []byte, label string, transcript fips140.Hash) []byte {
if transcript == nil {
transcript = hash()
}
return ExpandLabel(hash, secret, label, transcript.Sum(nil), transcript.Size())
}
const (
resumptionBinderLabel = "res binder"
clientEarlyTrafficLabel = "c e traffic"
clientHandshakeTrafficLabel = "c hs traffic"
serverHandshakeTrafficLabel = "s hs traffic"
clientApplicationTrafficLabel = "c ap traffic"
serverApplicationTrafficLabel = "s ap traffic"
earlyExporterLabel = "e exp master"
exporterLabel = "exp master"
resumptionLabel = "res master"
)
type EarlySecret struct {
secret []byte
hash func() fips140.Hash
}
func NewEarlySecret[H fips140.Hash](hash func() H, psk []byte) *EarlySecret {
return &EarlySecret{
secret: extract(hash, psk, nil),
hash: func() fips140.Hash { return hash() },
}
}
func (s *EarlySecret) ResumptionBinderKey() []byte {
return deriveSecret(s.hash, s.secret, resumptionBinderLabel, nil)
}
// ClientEarlyTrafficSecret derives the client_early_traffic_secret from the
// early secret and the transcript up to the ClientHello.
func (s *EarlySecret) ClientEarlyTrafficSecret(transcript fips140.Hash) []byte {
return deriveSecret(s.hash, s.secret, clientEarlyTrafficLabel, transcript)
}
type HandshakeSecret struct {
secret []byte
hash func() fips140.Hash
}
func (s *EarlySecret) HandshakeSecret(sharedSecret []byte) *HandshakeSecret {
derived := deriveSecret(s.hash, s.secret, "derived", nil)
return &HandshakeSecret{
secret: extract(s.hash, sharedSecret, derived),
hash: s.hash,
}
}
// ClientHandshakeTrafficSecret derives the client_handshake_traffic_secret from
// the handshake secret and the transcript up to the ServerHello.
func (s *HandshakeSecret) ClientHandshakeTrafficSecret(transcript fips140.Hash) []byte {
return deriveSecret(s.hash, s.secret, clientHandshakeTrafficLabel, transcript)
}
// ServerHandshakeTrafficSecret derives the server_handshake_traffic_secret from
// the handshake secret and the transcript up to the ServerHello.
func (s *HandshakeSecret) ServerHandshakeTrafficSecret(transcript fips140.Hash) []byte {
return deriveSecret(s.hash, s.secret, serverHandshakeTrafficLabel, transcript)
}
type MasterSecret struct {
secret []byte
hash func() fips140.Hash
}
func (s *HandshakeSecret) MasterSecret() *MasterSecret {
derived := deriveSecret(s.hash, s.secret, "derived", nil)
return &MasterSecret{
secret: extract(s.hash, nil, derived),
hash: s.hash,
}
}
// ClientApplicationTrafficSecret derives the client_application_traffic_secret_0
// from the master secret and the transcript up to the server Finished.
func (s *MasterSecret) ClientApplicationTrafficSecret(transcript fips140.Hash) []byte {
return deriveSecret(s.hash, s.secret, clientApplicationTrafficLabel, transcript)
}
// ServerApplicationTrafficSecret derives the server_application_traffic_secret_0
// from the master secret and the transcript up to the server Finished.
func (s *MasterSecret) ServerApplicationTrafficSecret(transcript fips140.Hash) []byte {
return deriveSecret(s.hash, s.secret, serverApplicationTrafficLabel, transcript)
}
// ResumptionMasterSecret derives the resumption_master_secret from the master secret
// and the transcript up to the client Finished.
func (s *MasterSecret) ResumptionMasterSecret(transcript fips140.Hash) []byte {
return deriveSecret(s.hash, s.secret, resumptionLabel, transcript)
}
type ExporterMasterSecret struct {
secret []byte
hash func() fips140.Hash
}
// ExporterMasterSecret derives the exporter_master_secret from the master secret
// and the transcript up to the server Finished.
func (s *MasterSecret) ExporterMasterSecret(transcript fips140.Hash) *ExporterMasterSecret {
return &ExporterMasterSecret{
secret: deriveSecret(s.hash, s.secret, exporterLabel, transcript),
hash: s.hash,
}
}
// EarlyExporterMasterSecret derives the exporter_master_secret from the early secret
// and the transcript up to the ClientHello.
func (s *EarlySecret) EarlyExporterMasterSecret(transcript fips140.Hash) *ExporterMasterSecret {
return &ExporterMasterSecret{
secret: deriveSecret(s.hash, s.secret, earlyExporterLabel, transcript),
hash: s.hash,
}
}
func (s *ExporterMasterSecret) Exporter(label string, context []byte, length int) []byte {
secret := deriveSecret(s.hash, s.secret, label, nil)
h := s.hash()
h.Write(context)
return ExpandLabel(s.hash, secret, "exporter", h.Sum(nil), length)
}
func TestingOnlyExporterSecret(s *ExporterMasterSecret) []byte {
return s.secret
}

26
internal/tls13/u_tls13.go Normal file
View file

@ -0,0 +1,26 @@
package tls13
import fips140 "hash"
func NewEarlySecretFromSecret[H fips140.Hash](hash func() H, secret []byte) *EarlySecret {
return &EarlySecret{
secret: secret,
hash: func() fips140.Hash { return hash() },
}
}
func (s *EarlySecret) Secret() []byte {
if s != nil {
return s.secret
}
return nil
}
func NewMasterSecretFromSecret[H fips140.Hash](hash func() H, secret []byte) *MasterSecret {
return &MasterSecret{
secret: secret,
hash: func() fips140.Hash { return hash() },
}
}
func (s *MasterSecret) Secret() []byte { return s.secret }

View file

@ -7,93 +7,27 @@ package tls
import (
"crypto/ecdh"
"crypto/hmac"
"crypto/mlkem"
"errors"
"fmt"
"hash"
"io"
"github.com/refraction-networking/utls/internal/mlkem768"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/hkdf"
"golang.org/x/crypto/sha3"
"github.com/refraction-networking/utls/internal/tls13"
)
// 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 +35,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,51 +43,17 @@ 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
}
}
type keySharePrivateKeys struct {
curveID CurveID
ecdhe *ecdh.PrivateKey
kyber *mlkem768.DecapsulationKey
}
// kyberDecapsulate implements decapsulation according to Kyber Round 3.
func kyberDecapsulate(dk *mlkem768.DecapsulationKey, c []byte) ([]byte, error) {
K, err := mlkem768.Decapsulate(dk, c)
if err != nil {
return nil, err
}
return kyberSharedSecret(K, c), nil
}
// kyberEncapsulate implements encapsulation according to Kyber Round 3.
func kyberEncapsulate(ek []byte) (c, ss []byte, err error) {
c, ss, err = mlkem768.Encapsulate(ek)
if err != nil {
return nil, nil, err
}
return c, kyberSharedSecret(ss, c), nil
}
func kyberSharedSecret(K, c []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.
h := sha3.NewShake256()
h.Write(K)
ch := sha3.Sum256(c)
h.Write(ch[:])
out := make([]byte, 32)
h.Read(out)
return out
mlkem *mlkem.DecapsulationKey768
}
const x25519PublicKeySize = 32

View file

@ -6,15 +6,81 @@ package tls
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"hash"
"strings"
"testing"
"unicode"
"github.com/refraction-networking/utls/internal/mlkem768"
"github.com/refraction-networking/utls/internal/tls13"
)
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 {
@ -33,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,90 +118,3 @@ func TestTrafficKey(t *testing.T) {
t.Errorf("cipherSuiteTLS13.trafficKey() gotIV = % x, want % x", gotIV, wantIV)
}
}
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")
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 {
t.Fatal(err)
}
ct, ss, err := kyberEncapsulate(dk.EncapsulationKey())
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)
}
}

View file

@ -1,6 +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.
package tls
func needFIPS() bool { return false }

64
prf.go
View file

@ -14,8 +14,12 @@ import (
"errors"
"fmt"
"hash"
"github.com/refraction-networking/utls/internal/tls12"
)
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 +49,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 +66,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 +82,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 +102,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 +114,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 +138,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 +181,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 +213,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 +292,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
}
}

View file

@ -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 {

View file

@ -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 |.<U..Po..L>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|

View file

@ -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 |.<TD..s.v......'|
00000300 97 b1 e9 31 37 ea a7 5d a9 00 ce 85 08 5a b3 ac |...17..].....Z..|
00000310 ef a6 8d c3 9f a5 ba 97 e8 bc 9f 81 63 77 7b 2e |............cw{.|
00000320 92 5f 36 a1 00 04 c1 3f e9 76 bb 58 da aa 03 ba |._6....?.v.X....|
00000330 cd 11 9b 9a 56 2e 64 53 74 b4 62 00 89 4a 57 0f |....V.dSt.b..JW.|
00000340 a2 a9 f2 16 17 ab a3 72 3d 16 4d 41 4a df 54 b1 |.......r=.MAJ.T.|
00000350 72 ab 8b bf a3 74 af 1c 30 d0 75 27 a6 ce a1 56 |r....t..0.u'...V|
00000360 ec 08 f9 c0 c9 9d 71 7a 83 a4 bd 33 af 7a 5e 16 |......qz...3.z^.|
000002c0 16 03 01 00 aa 0c 00 00 a6 03 00 1d 20 fc 77 2f |............ .w/|
000002d0 88 9a a9 71 3a 14 bf 27 27 40 e0 28 ce e8 e8 3b |...q:..''@.(...;|
000002e0 cd 0a 43 21 75 c9 93 70 9a 22 f1 ec 3a 00 80 d2 |..C!u..p."..:...|
000002f0 cd 71 ae f6 d8 54 5c f3 a4 da c7 64 51 b8 36 b8 |.q...T\....dQ.6.|
00000300 46 d5 8c b1 a0 43 9b f2 b5 2c 12 89 08 39 2b c3 |F....C...,...9+.|
00000310 79 4e 5d 3d 7e 7f d5 51 c3 c5 1e 9e 3b 7c 39 c4 |yN]=~..Q....;|9.|
00000320 c3 64 52 91 94 2f 2c ee aa 7c 0e ed fd 7a 65 bb |.dR../,..|...ze.|
00000330 5a 62 f4 45 24 3d e7 e3 f2 8a 72 74 a7 9d f2 d5 |Zb.E$=....rt....|
00000340 69 be dc 6e 23 fb 68 bb 6e 64 9e 43 a8 f4 08 2b |i..n#.h.nd.C...+|
00000350 86 be ea 88 40 13 5f 3f 0b 18 74 e3 43 76 be 98 |....@._?..t.Cv..|
00000360 b8 15 ea 4d cb 6e 23 3c 8b a9 ce d4 6a e3 13 16 |...M.n#<....j...|
00000370 03 01 00 0a 0d 00 00 06 03 01 02 40 00 00 16 03 |...........@....|
00000380 01 00 04 0e 00 00 00 |.......|
>>> 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..<mG\.|
00000040 a6 a1 81 65 e6 e9 b1 05 e0 45 15 03 01 00 20 4e |...e.....E.... N|
00000050 92 00 b5 bc b9 b8 c6 fe d1 5c d1 93 f8 cd 7c 3f |.........\....|?|
00000060 bd 47 82 ff b0 00 3b 96 f0 7a 3b a4 cc 15 f3 |.G....;..z;....|
00000000 17 03 01 00 20 e5 74 9a b9 0b 6c 43 0f 4e db e4 |.... .t...lC.N..|
00000010 ba 10 5d 9a f0 96 16 17 ad a5 42 d8 0d a3 39 86 |..].......B...9.|
00000020 6c f0 8a 64 70 17 03 01 00 20 d2 11 27 ea f2 80 |l..dp.... ..'...|
00000030 a5 5d ba 7b 99 4b 94 25 13 24 29 05 7b 64 00 51 |.].{.K.%.$).{d.Q|
00000040 14 8e d5 e9 e2 c0 5d 98 96 30 15 03 01 00 20 7e |......]..0.... ~|
00000050 87 d2 6c 5c b5 1c 11 72 e1 c4 e5 e0 f3 16 6b db |..l\...r......k.|
00000060 55 c3 c7 ae a9 38 d3 07 04 41 be c5 42 43 a4 |U....8...A..BC.|

View file

@ -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 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...|

View file

@ -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.|

View file

@ -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.<o..-.L......|
00000070 41 46 1a 0a 93 cf 12 33 c4 79 41 aa 73 fc 12 14 |AF.....3.yA.s...|
00000080 03 03 00 01 01 17 03 03 00 17 7d c4 d7 dd 02 23 |..........}....#|
00000090 a5 5b 1f 1b 31 ba fa 77 21 9f a0 21 bd 94 19 e3 |.[..1..w!..!....|
000000a0 44 17 03 03 00 42 b7 5e 0d fe db fd 32 64 15 d2 |D....B.^....2d..|
000000b0 b6 14 7f 18 fe 39 f3 50 c2 d4 0d 36 cd 60 e7 49 |.....9.P...6.`.I|
000000c0 e1 eb fe 36 be ec dd b1 3a 75 d4 12 b1 13 7d eb |...6....:u....}.|
000000d0 a0 47 18 4a e1 b4 1c 1f 91 33 5f a7 99 28 89 d0 |.G.J.....3_..(..|
000000e0 0e 4e 79 9e be 5c 7e 36 17 03 03 02 6d 0b b3 0e |.Ny..\~6....m...|
000000f0 03 f8 e4 35 b7 d5 3f 3e 8c 8c a1 dc a3 b5 0c 74 |...5..?>.......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<Zv.th|
00000230 63 cc 5c 0c de e2 30 b8 c0 46 13 78 c5 92 97 7f |c.\...0..F.x....|
00000240 23 74 0b 54 4e ea 6e 5d bd 8e b8 89 12 2c 01 b0 |#t.TN.n].....,..|
00000250 ed 03 4d 67 1e 96 22 03 77 78 d1 4f c0 b7 4a 71 |..Mg..".wx.O..Jq|
00000260 6b 11 a3 c4 18 7a da c4 b5 7b 78 74 21 f5 44 49 |k....z...{xt!.DI|
00000270 70 0e 78 34 fb 66 ed a1 86 52 3c 93 de 17 a1 4d |p.x4.f...R<....M|
00000280 4a f3 f6 9e ff f8 e1 18 b9 80 12 9a 34 7a 58 bb |J...........4zX.|
00000290 7a aa 95 d0 c7 a7 88 d2 d3 86 bf 7a c9 e3 fc 83 |z..........z....|
000002a0 c6 b9 db ee ad eb b8 fd 4b 82 4f 34 9d eb 45 eb |........K.O4..E.|
000002b0 33 19 aa a5 b6 82 47 b3 5b f4 e7 be f0 49 bd 76 |3.....G.[....I.v|
000002c0 41 82 8d 09 86 82 cb 45 12 f8 aa 9a 99 43 da 31 |A......E.....C.1|
000002d0 4f cb 9e c4 f6 a0 40 85 2b 9d 55 6e 15 66 b5 f8 |O.....@.+.Un.f..|
000002e0 0b 3e 0e aa 4b aa 2e 6b 2a 44 3f ea 23 d5 ab 55 |.>..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.<v.|
00000170 1f 54 73 11 8a ee 25 da 54 18 9d ce c5 4c 97 ef |.Ts...%.T....L..|
00000180 a9 3a 83 1f dc 8f 18 48 87 64 6e 9d 01 db 7d a7 |.:.....H.dn...}.|
00000190 46 28 11 6d 45 83 04 43 b0 71 23 b7 84 20 ab 98 |F(.mE..C.q#.. ..|
000001a0 f2 e0 f5 3e 66 44 63 4b 43 e6 25 28 44 d2 2d 04 |...>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..&..".......(|

View file

@ -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|

View file

@ -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..<B|
00000040 c4 0a d1 08 36 64 8e bd 0a 2f a2 17 03 03 00 40 |....6d.../.....@|
00000010 00 00 00 00 00 00 00 00 00 00 00 c3 13 7d 0a ed |.............}..|
00000020 12 16 0f a5 e9 09 bb 38 9e bb 25 3f d3 36 f2 57 |.......8..%?.6.W|
00000030 37 2b cf c7 9e d4 ed b6 ee 0e 07 8e a7 ae 71 c9 |7+............q.|
00000040 1e cb 40 65 8b c5 9c e0 14 c5 f3 17 03 03 00 40 |..@e...........@|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 ef 16 5e cb e7 c4 2d a8 76 77 da 18 91 bd cb 78 |..^...-.vw.....x|
00000070 76 c5 5d 70 e5 ba 57 2a 1f 2b 11 3f 18 18 e6 1b |v.]p..W*.+.?....|
00000080 36 78 c9 f1 5e 71 f1 71 f1 01 31 e6 37 fa 76 92 |6x..^q.q..1.7.v.|
00000060 0d 8e c2 8a a5 5a 8b bc d8 86 a0 05 cf c6 39 a7 |.....Z........9.|
00000070 6d 65 f1 a7 bb 74 25 1d 3e 75 fd f8 1f a5 06 b6 |me...t%.>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.|

View file

@ -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 |_..<p.g.....+...|
00000420 64 f4 bc 22 35 20 7f ff 64 b3 be d9 eb a1 ab 5d |d.."5 ..d......]|
00000430 d9 3b ae 30 46 76 70 48 04 43 |.;.0FvpH.C|
00000080 03 03 00 01 01 17 03 03 00 17 55 0c 9b 36 df 28 |..........U..6.(|
00000090 4c fb 72 f6 89 a1 7f e2 3e 9f ab 62 c7 8d b8 4f |L.r.....>..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 |.....^<P.n.3..H.|
000001c0 81 c4 ae 6d 64 f6 85 36 73 7d f7 35 a2 71 39 9d |...md..6s}.5.q9.|
000001d0 09 06 dc 78 14 36 0a c6 4e c5 ef 28 1b f9 72 e3 |...x.6..N..(..r.|
000001e0 4e dc 9d 4f 29 63 67 68 38 27 66 ff d5 9d d6 e6 |N..O)cgh8'f.....|
000001f0 60 be ac 8e 7f 59 0b 29 e8 5b f0 45 c1 86 22 e4 |`....Y.).[.E..".|
00000200 14 4f f2 8d 7b 42 5f c8 f5 74 cc 7e 49 fb 43 ad |.O..{B_..t.~I.C.|
00000210 67 ec 70 b8 47 bb 50 74 fb 65 49 22 03 d4 81 6f |g.p.G.Pt.eI"...o|
00000220 fc 2a 22 7b 2a 26 6d 51 8f 7b f2 53 d3 25 d2 19 |.*"{*&mQ.{.S.%..|
00000230 f1 d6 19 a9 6f bd a1 4c 01 80 f0 ba db 6d 0a e2 |....o..L.....m..|
00000240 1b 54 78 c1 b3 d3 f4 de 6f 78 97 71 ff 39 dd 88 |.Tx.....ox.q.9..|
00000250 c2 56 3e aa a6 7d d0 8f da ee a4 48 55 42 c3 14 |.V>..}.....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 |!.....]....|

View file

@ -47,10 +47,6 @@ var supportedSignatureAlgorithmsWithCircl []SignatureScheme
// schemes are only included when tls.Config#PQSignatureSchemesEnabled is set
// and FIPS-only mode is not enabled.
func (c *Config) supportedSignatureAlgorithms() []SignatureScheme {
// If FIPS-only mode is requested, do not add other algos.
if needFIPS() {
return supportedSignatureAlgorithms()
}
if c != nil && c.PQSignatureSchemesEnabled {
return supportedSignatureAlgorithmsWithCircl
}

View file

@ -8,6 +8,7 @@ import (
"bytes"
"context"
"crypto"
"crypto/ecdh"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
@ -28,6 +29,10 @@ import (
"testing"
"time"
"golang.org/x/crypto/cryptobyte"
"github.com/refraction-networking/utls/internal/fips140tls"
"github.com/refraction-networking/utls/internal/hpke"
"github.com/refraction-networking/utls/testenv"
)
@ -163,6 +168,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")
@ -173,6 +179,12 @@ func newLocalListener(t testing.TB) net.Listener {
return ln
}
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")
@ -883,6 +895,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
case "ApplicationSettings": // [UTLS] ALPS (Application Settings)
@ -1113,6 +1129,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)
@ -1120,8 +1138,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")}
@ -1137,7 +1153,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,
@ -1253,6 +1269,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,
@ -1702,6 +1720,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) })
@ -1768,7 +1788,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
@ -1845,24 +1865,21 @@ func testVerifyCertificates(t *testing.T, version uint16) {
}
}
func TestHandshakeKyber(t *testing.T) {
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,
},
{
@ -1878,7 +1895,7 @@ func TestHandshakeKyber(t *testing.T) {
config.CurvePreferences = []CurveID{X25519}
},
expectClientSupport: true,
expectKyber: false,
expectMLKEM: false,
expectHRR: false,
},
{
@ -1887,9 +1904,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) {
@ -1903,8 +1936,17 @@ func TestHandshakeKyber(t *testing.T) {
config.MaxVersion = VersionTLS12
},
expectClientSupport: true,
expectKyber: false,
expectMLKEM: false,
},
// [uTLS] SECTION BEGIN
// {
// name: "GODEBUG",
// preparation: func(t *testing.T) {
// t.Setenv("GODEBUG", "tlsmlkem=0")
// },
// expectClientSupport: false,
// },
// [uTLS] SECTION END
}
baseConfig := testConfig.Clone()
@ -1921,10 +1963,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
}
@ -1936,19 +1978,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 {
@ -2021,6 +2063,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")
}
}

View file

@ -88,7 +88,7 @@ const (
)
const (
X25519Kyber768Draft00 CurveID = x25519Kyber768Draft00
// X25519Kyber768Draft00 CurveID = x25519Kyber768Draft00
FakeCurveX25519Kyber512Draft00 CurveID = 0xfe30
FakeCurveX25519Kyber768Draft00Old CurveID = 0xfe31

View file

@ -53,7 +53,7 @@ type UConn struct {
ech ECHExtension
// echCtx is the echContex returned by makeClientHello()
echCtx *echContext
echCtx *echClientContext
}
// UClient returns a new uTLS client, with behavior depending on clientHelloID.

View file

@ -14,7 +14,9 @@ import (
"github.com/andybalholm/brotli"
"github.com/klauspost/compress/zstd"
"github.com/refraction-networking/utls/internal/fips140tls"
"github.com/refraction-networking/utls/internal/hpke"
"github.com/refraction-networking/utls/internal/tls13"
)
// This function is called by (*clientHandshakeStateTLS13).readServerCertificate()
@ -183,7 +185,7 @@ func (hs *clientHandshakeStateTLS13) utlsReadServerParameters(encryptedExtension
return nil
}
func (c *Conn) makeClientHelloForApplyPreset() (*clientHelloMsg, *keySharePrivateKeys, *echContext, error) {
func (c *Conn) makeClientHelloForApplyPreset() (*clientHelloMsg, *keySharePrivateKeys, *echClientContext, error) {
config := c.config
// [UTLS SECTION START]
@ -286,35 +288,44 @@ func (c *Conn) makeClientHelloForApplyPreset() (*clientHelloMsg, *keySharePrivat
if len(hello.supportedVersions) == 1 {
hello.cipherSuites = nil
}
if hasAESGCMHardwareSupport {
if fips140tls.Required() {
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 {
// // 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
// }
// 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.NewKeyFromSeed(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()...)},
// {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 {
@ -340,7 +351,7 @@ func (c *Conn) makeClientHelloForApplyPreset() (*clientHelloMsg, *keySharePrivat
// 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")
@ -356,7 +367,7 @@ func (c *Conn) makeClientHelloForApplyPreset() (*clientHelloMsg, *keySharePrivat
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
@ -433,7 +444,7 @@ func (c *UConn) clientHandshake(ctx context.Context) (err error) {
var (
session *SessionState
earlySecret []byte
earlySecret *tls13.EarlySecret
binderKey []byte
)
if !sessionIsLocked {
@ -444,7 +455,12 @@ func (c *UConn) clientHandshake(ctx context.Context) (err error) {
// [uTLS section start]
} else {
session = c.HandshakeState.Session
earlySecret = c.HandshakeState.State13.EarlySecret
if c.HandshakeState.State13.EarlySecret != nil && session != nil {
cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite)
earlySecret = tls13.NewEarlySecretFromSecret(cipherSuite.hash.New, c.HandshakeState.State13.EarlySecret)
}
binderKey = c.HandshakeState.State13.BinderKey
}
// [uTLS section ends]
@ -502,7 +518,7 @@ func (c *UConn) 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)
}
@ -528,6 +544,12 @@ func (c *UConn) clientHandshake(ctx context.Context) (err error) {
hs13.serverHello = serverHello
hs13.hello = hello
hs13.echContext = ech
if c.HandshakeState.State13.EarlySecret != nil && session.cipherSuite != 0 {
hs13.earlySecret = tls13.NewEarlySecretFromSecret(cipherSuiteTLS13ByID(session.cipherSuite).hash.New, c.HandshakeState.State13.EarlySecret)
}
if c.HandshakeState.MasterSecret != nil && session.cipherSuite != 0 {
hs13.masterSecret = tls13.NewMasterSecretFromSecret(cipherSuiteTLS13ByID(session.cipherSuite).hash.New, c.HandshakeState.MasterSecret)
}
if !sessionIsLocked {
hs13.earlySecret = earlySecret
hs13.binderKey = binderKey

View file

@ -5,6 +5,7 @@
package tls
import (
"crypto/mlkem"
crand "crypto/rand"
"crypto/sha256"
"encoding/binary"
@ -18,7 +19,6 @@ import (
"strconv"
"github.com/refraction-networking/utls/dicttls"
"github.com/refraction-networking/utls/internal/mlkem768"
)
var ErrUnknownClientHelloID = errors.New("tls: unknown ClientHelloID")
@ -618,7 +618,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
GREASE_PLACEHOLDER,
X25519Kyber768Draft00,
X25519MLKEM768,
X25519,
CurveP256,
CurveP384,
@ -642,7 +642,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519Kyber768Draft00},
{Group: X25519MLKEM768},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
@ -764,7 +764,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
GREASE_PLACEHOLDER,
X25519Kyber768Draft00,
X25519MLKEM768,
X25519,
CurveP256,
CurveP384,
@ -788,7 +788,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519Kyber768Draft00},
{Group: X25519MLKEM768},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
@ -2495,7 +2495,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
&RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
&SupportedCurvesExtension{[]CurveID{
GREASE_PLACEHOLDER,
X25519Kyber768Draft00,
X25519MLKEM768,
X25519,
CurveP256,
CurveP384,
@ -2519,7 +2519,7 @@ func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
&SCTExtension{},
&KeyShareExtension{[]KeyShare{
{Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
{Group: X25519Kyber768Draft00},
{Group: X25519MLKEM768},
{Group: X25519},
}},
&PSKKeyExchangeModesExtension{[]uint8{
@ -2736,37 +2736,37 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error {
continue
}
if curveID == x25519Kyber768Draft00 {
if curveID == X25519MLKEM768 {
ecdheKey, err := generateECDHEKey(uconn.config.rand(), X25519)
if err != nil {
return err
}
seed := make([]byte, mlkem768.SeedSize)
seed := make([]byte, mlkem.SeedSize)
if _, err := io.ReadFull(uconn.config.rand(), seed); err != nil {
return err
}
kyberKey, err := mlkem768.NewKeyFromSeed(seed)
mlkemKey, err := mlkem.NewDecapsulationKey768(seed)
if err != nil {
return err
}
circlKyberKey, err := kyberGoToCircl(kyberKey, ecdheKey)
if err != nil {
return err
}
uconn.HandshakeState.State13.KeySharesParams.AddKemKeypair(curveID, circlKyberKey, circlKyberKey.Public())
// circlKyberKey, err := kyberGoToCircl(kyberKey, ecdheKey)
// if err != nil {
// return err
// }
// uconn.HandshakeState.State13.KeySharesParams.AddKemKeypair(curveID, circlKyberKey, circlKyberKey.Public())
ext.KeyShares[i].Data = append(ecdheKey.PublicKey().Bytes(), kyberKey.EncapsulationKey()...)
ext.KeyShares[i].Data = append(mlkemKey.EncapsulationKey().Bytes(), ecdheKey.PublicKey().Bytes()...)
if !preferredCurveIsSet {
// only do this once for the first non-grease curve
uconn.HandshakeState.State13.KeyShareKeys.kyber = kyberKey
uconn.HandshakeState.State13.KeyShareKeys.mlkem = mlkemKey
preferredCurveIsSet = true
}
if len(ext.KeyShares) > i+1 && ext.KeyShares[i+1].Group == X25519 {
// Reuse the same X25519 ephemeral key for both keyshares, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2.
uconn.HandshakeState.State13.KeyShareKeys.Ecdhe = ecdheKey
uconn.HandshakeState.State13.KeySharesParams.AddEcdheKeypair(curveID, ecdheKey, ecdheKey.PublicKey())
// uconn.HandshakeState.State13.KeySharesParams.AddEcdheKeypair(curveID, ecdheKey, ecdheKey.PublicKey())
ext.KeyShares[i+1].Data = ecdheKey.PublicKey().Bytes()
}
} else {
@ -2776,7 +2776,7 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error {
"To mimic it, fill the Data(key) field manually", curveID)
}
uconn.HandshakeState.State13.KeySharesParams.AddEcdheKeypair(curveID, ecdheKey, ecdheKey.PublicKey())
// uconn.HandshakeState.State13.KeySharesParams.AddEcdheKeypair(curveID, ecdheKey, ecdheKey.PublicKey())
ext.KeyShares[i].Data = ecdheKey.PublicKey().Bytes()
if !preferredCurveIsSet {

View file

@ -7,14 +7,12 @@ package tls
import (
"crypto"
"crypto/ecdh"
"crypto/mlkem"
"crypto/x509"
"fmt"
"hash"
"time"
"github.com/cloudflare/circl/kem"
"github.com/cloudflare/circl/kem/hybrid"
"github.com/refraction-networking/utls/internal/mlkem768"
)
// ClientHandshakeState includes both TLS 1.3-only and TLS 1.2-only states,
@ -64,45 +62,45 @@ type TLS12OnlyState struct {
Suite PubCipherSuite
}
func mlkemCirclToGo(circlKey kem.PrivateKey) (*mlkem768.DecapsulationKey, *ecdh.PrivateKey, error) {
if circlKey.Scheme().Name() != "Kyber768-X25519" {
return nil, nil, fmt.Errorf("circl key is not Kyber768-X25519")
}
// func mlkemCirclToGo(circlKey kem.PrivateKey) (*mlkem768.DecapsulationKey, *ecdh.PrivateKey, error) {
// if circlKey.Scheme().Name() != "Kyber768-X25519" {
// return nil, nil, fmt.Errorf("circl key is not Kyber768-X25519")
// }
encodedKey, err := circlKey.MarshalBinary()
if err != nil {
return nil, nil, err
}
// encodedKey, err := circlKey.MarshalBinary()
// if err != nil {
// return nil, nil, err
// }
ecdhKey := encodedKey[:x25519PublicKeySize]
kyberKey := encodedKey[x25519PublicKeySize:]
// ecdhKey := encodedKey[:x25519PublicKeySize]
// kyberKey := encodedKey[x25519PublicKeySize:]
goKyberkey, err := mlkem768.NewKeyFromExtendedEncoding(kyberKey)
if err != nil {
return nil, nil, err
}
// goKyberkey, err := mlkem768.NewKeyFromExtendedEncoding(kyberKey)
// if err != nil {
// return nil, nil, err
// }
goEcdhKey, err := ecdh.X25519().NewPrivateKey(ecdhKey)
if err != nil {
return nil, nil, err
}
// goEcdhKey, err := ecdh.X25519().NewPrivateKey(ecdhKey)
// if err != nil {
// return nil, nil, err
// }
return goKyberkey, goEcdhKey, nil
}
// return goKyberkey, goEcdhKey, nil
// }
func (chs *TLS13OnlyState) private13KeyShareKeys() *keySharePrivateKeys {
if chs.KeyShareKeys != nil {
return chs.KeyShareKeys.ToPrivate()
}
if chs.KEMKey != nil {
if kyberKey, ecdhKey, err := mlkemCirclToGo(chs.KEMKey.SecretKey); err == nil {
return &keySharePrivateKeys{
kyber: kyberKey,
ecdhe: ecdhKey,
}
}
}
// if chs.KEMKey != nil {
// if kyberKey, ecdhKey, err := mlkemCirclToGo(chs.KEMKey.SecretKey); err == nil {
// return &keySharePrivateKeys{
// kyber: kyberKey,
// ecdhe: ecdhKey,
// }
// }
// }
if chs.EcdheKey != nil {
return &keySharePrivateKeys{
@ -113,9 +111,9 @@ func (chs *TLS13OnlyState) private13KeyShareKeys() *keySharePrivateKeys {
return nil
}
func kyberGoToCircl(kyberKey *mlkem768.DecapsulationKey, ecdhKey *ecdh.PrivateKey) (kem.PrivateKey, error) {
return hybrid.Kyber768X25519().UnmarshalBinaryPrivateKey(append(ecdhKey.Bytes(), kyberKey.Bytes()...))
}
// func kyberGoToCircl(kyberKey *mlkem768.DecapsulationKey, ecdhKey *ecdh.PrivateKey) (kem.PrivateKey, error) {
// return hybrid.Kyber768X25519().UnmarshalBinaryPrivateKey(append(ecdhKey.Bytes(), kyberKey.Bytes()...))
// }
func (chs *PubClientHandshakeState) toPrivate13() *clientHandshakeStateTLS13 {
if chs == nil {
@ -128,16 +126,14 @@ func (chs *PubClientHandshakeState) toPrivate13() *clientHandshakeStateTLS13 {
keyShareKeys: chs.State13.private13KeyShareKeys(),
keySharesParams: chs.State13.KeySharesParams,
session: chs.Session,
earlySecret: chs.State13.EarlySecret,
binderKey: chs.State13.BinderKey,
session: chs.Session,
binderKey: chs.State13.BinderKey,
certReq: chs.State13.CertReq.toPrivate(),
usingPSK: chs.State13.UsingPSK,
sentDummyCCS: chs.State13.SentDummyCCS,
suite: chs.State13.Suite.toPrivate(),
transcript: chs.State13.Transcript,
masterSecret: chs.MasterSecret,
trafficSecret: chs.State13.TrafficSecret,
uconn: chs.uconn,
@ -152,7 +148,7 @@ func (chs13 *clientHandshakeStateTLS13) toPublic13() *PubClientHandshakeState {
tls13State := TLS13OnlyState{
KeySharesParams: chs13.keySharesParams,
KeyShareKeys: chs13.keyShareKeys.ToPublic(),
EarlySecret: chs13.earlySecret,
EarlySecret: chs13.earlySecret.Secret(),
BinderKey: chs13.binderKey,
CertReq: chs13.certReq.toPublic(),
UsingPSK: chs13.usingPSK,
@ -168,7 +164,7 @@ func (chs13 *clientHandshakeStateTLS13) toPublic13() *PubClientHandshakeState {
Session: chs13.session,
MasterSecret: chs13.masterSecret,
MasterSecret: chs13.masterSecret.Secret(),
State13: tls13State,
@ -599,22 +595,48 @@ type FinishedHash struct {
Buffer []byte
Version uint16
Prf func(result, secret, label, seed []byte)
Prfv2 prfFunc
// Deprecated: Use Prfv2 instead. Prfv2 will be used if both are set.
Prf prfFuncOld
}
type prfFuncOld func(result, secret, label, seed []byte)
func prfFuncV1ToV2(v1 prfFuncOld) prfFunc {
return func(secret []byte, label string, seed []byte, keyLen int) []byte {
res := make([]byte, keyLen)
v1(res, secret, []byte(label), seed)
return res
}
}
func prfFuncV2ToV1(v2 prfFunc) prfFuncOld {
return func(result, secret, label, seed []byte) {
copy(result, v2(secret, string(label), seed, len(result)))
}
}
func (fh *FinishedHash) getPrivateObj() finishedHash {
if fh == nil {
return finishedHash{}
} else {
return finishedHash{
res := finishedHash{
client: fh.Client,
server: fh.Server,
clientMD5: fh.ClientMD5,
serverMD5: fh.ServerMD5,
buffer: fh.Buffer,
version: fh.Version,
prf: fh.Prf,
}
if fh.Prfv2 != nil {
res.prf = fh.Prfv2
} else if fh.Prf != nil {
res.prf = prfFuncV1ToV2(fh.Prf)
}
return res
}
}
@ -622,14 +644,19 @@ func (fh *finishedHash) getPublicObj() FinishedHash {
if fh == nil {
return FinishedHash{}
} else {
return FinishedHash{
res := FinishedHash{
Client: fh.client,
Server: fh.server,
ClientMD5: fh.clientMD5,
ServerMD5: fh.serverMD5,
Buffer: fh.buffer,
Version: fh.version,
Prf: fh.prf}
}
res.Prfv2 = fh.prf
res.Prf = prfFuncV2ToV1(fh.prf)
return res
}
}
@ -894,14 +921,14 @@ func (kpk *kemPrivateKey) ToPublic() *KemPrivateKey {
type KeySharePrivateKeys struct {
CurveID CurveID
Ecdhe *ecdh.PrivateKey
kyber *mlkem768.DecapsulationKey
mlkem *mlkem.DecapsulationKey768
}
func (ksp *KeySharePrivateKeys) ToPrivate() *keySharePrivateKeys {
return &keySharePrivateKeys{
curveID: ksp.CurveID,
ecdhe: ksp.Ecdhe,
kyber: ksp.kyber,
mlkem: ksp.mlkem,
}
}
@ -909,6 +936,6 @@ func (ksp *keySharePrivateKeys) ToPublic() *KeySharePrivateKeys {
return &KeySharePrivateKeys{
CurveID: ksp.curveID,
Ecdhe: ksp.ecdhe,
kyber: ksp.kyber,
mlkem: ksp.mlkem,
}
}

View file

@ -3,6 +3,8 @@ package tls
import (
"errors"
"fmt"
"github.com/refraction-networking/utls/internal/tls13"
)
// Tracking the state of calling conn.loadSession
@ -161,7 +163,7 @@ func (s *sessionController) initSessionTicketExt(session *SessionState, ticket [
// initPSK initializes the PSK extension using a valid session. The PSK extension
// should not be initialized previously, and the parameters must not be nil;
// otherwise, this function will trigger a panic.
func (s *sessionController) initPskExt(session *SessionState, earlySecret []byte, binderKey []byte, pskIdentities []pskIdentity) {
func (s *sessionController) initPskExt(session *SessionState, earlySecret *tls13.EarlySecret, binderKey []byte, pskIdentities []pskIdentity) {
s.assertNotLocked("initPskExt")
s.assertHelloNotBuilt("initPskExt")
s.assertControllerState("initPskExt", NoSession)
@ -177,7 +179,7 @@ func (s *sessionController) initPskExt(session *SessionState, earlySecret []byte
ObfuscatedTicketAge: private.obfuscatedTicketAge,
}
})
e.InitializeByUtls(session, earlySecret, binderKey, publicPskIdentities)
e.InitializeByUtls(session, earlySecret.Secret(), binderKey, publicPskIdentities)
})
s.state = PskExtInitialized

View file

@ -886,16 +886,6 @@ func (e *ExtendedMasterSecretExtension) Write(_ []byte) (int, error) {
return 0, nil
}
// var extendedMasterSecretLabel = []byte("extended master secret")
// extendedMasterFromPreMasterSecret generates the master secret from the pre-master
// secret and session hash. See https://tools.ietf.org/html/rfc7627#section-4
func extendedMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret []byte, sessionHash []byte) []byte {
masterSecret := make([]byte, masterSecretLength)
prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, sessionHash)
return masterSecret
}
// GREASE stinks with dead parrots, have to be super careful, and, if possible, not include GREASE
// https://github.com/google/boringssl/blob/1c68fa2350936ca5897a66b430ebaf333a0e43f5/ssl/internal.h
const (