mirror of
https://github.com/XTLS/REALITY.git
synced 2026-09-22 23:08:01 +03:00
Sync upstream Go 1.27+; Add "[REALITY] SECTION" comments (#30)
https://github.com/XTLS/REALITY/pull/30#issuecomment-5579024460 https://github.com/XTLS/REALITY/pull/30#issuecomment-5594872257 https://github.com/XTLS/REALITY/pull/38#discussion_r4058349112
This commit is contained in:
+82
-86
@@ -10,11 +10,11 @@ import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/mlkem"
|
||||
"crypto/hpke"
|
||||
"crypto/mldsa"
|
||||
"crypto/rsa"
|
||||
"crypto/subtle"
|
||||
"crypto/x509"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/xtls/reality/fips140tls"
|
||||
"github.com/xtls/reality/hpke"
|
||||
"github.com/xtls/reality/tls13"
|
||||
)
|
||||
|
||||
@@ -41,8 +40,6 @@ type clientHandshakeState struct {
|
||||
ticket []byte // a fresh ticket received during this handshake
|
||||
}
|
||||
|
||||
var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme
|
||||
|
||||
func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echClientContext, error) {
|
||||
config := c.config
|
||||
if len(config.ServerName) == 0 && !config.InsecureSkipVerify {
|
||||
@@ -61,7 +58,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCli
|
||||
return nil, nil, nil, errors.New("tls: NextProtos values too large")
|
||||
}
|
||||
|
||||
supportedVersions := config.supportedVersions(roleClient)
|
||||
supportedVersions := config.supportedVersions(roleClient, c.quic != nil)
|
||||
if len(supportedVersions) == 0 {
|
||||
return nil, nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
|
||||
}
|
||||
@@ -123,11 +120,8 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCli
|
||||
}
|
||||
|
||||
if maxVersion >= VersionTLS12 {
|
||||
hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms(minVersion)
|
||||
hello.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithmsCert()
|
||||
}
|
||||
if testingOnlyForceClientHelloSignatureAlgorithms != nil {
|
||||
hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
|
||||
hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms(minVersion, maxVersion)
|
||||
hello.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithmsCert(minVersion, maxVersion)
|
||||
}
|
||||
|
||||
var keyShareKeys *keySharePrivateKeys
|
||||
@@ -146,45 +140,23 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCli
|
||||
}
|
||||
|
||||
if len(hello.supportedCurves) == 0 {
|
||||
return nil, nil, nil, errors.New("tls: no supported elliptic curves for ECDHE")
|
||||
return nil, nil, nil, errors.New("tls: no supported key exchange methods (CurveIDs)")
|
||||
}
|
||||
// Since the order is fixed, the first one is always the one to send a
|
||||
// key share for. All the PQ hybrids sort first, and produce a fallback
|
||||
// ECDH share.
|
||||
curveID := hello.supportedCurves[0]
|
||||
keyShareKeys = &keySharePrivateKeys{curveID: curveID}
|
||||
// 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, mlkem.SeedSize)
|
||||
if _, err := io.ReadFull(config.rand(), seed); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
keyShareKeys.mlkem, err = mlkem.NewDecapsulationKey768(seed)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
mlkemEncapsulationKey := keyShareKeys.mlkem.EncapsulationKey().Bytes()
|
||||
x25519EphemeralKey := keyShareKeys.ecdhe.PublicKey().Bytes()
|
||||
hello.keyShares = []keyShare{
|
||||
{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 {
|
||||
return nil, nil, nil, errors.New("tls: CurvePreferences includes unsupported curve")
|
||||
}
|
||||
keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), curveID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
hello.keyShares = []keyShare{{group: curveID, data: keyShareKeys.ecdhe.PublicKey().Bytes()}}
|
||||
ke, err := keyExchangeForCurveID(curveID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.New("tls: internal error: supportsCurve accepted unimplemented curve")
|
||||
}
|
||||
keyShareKeys, hello.keyShares, err = ke.keyShares(config.rand())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
// Only send the fallback ECDH share if the corresponding CurveID is enabled.
|
||||
if len(hello.keyShares) == 2 && !slices.Contains(hello.supportedCurves, hello.keyShares[1].group) {
|
||||
hello.keyShares = hello.keyShares[:1]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,11 +183,11 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCli
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
echConfig := pickECHConfig(echConfigs)
|
||||
echConfig, echPK, kdf, aead := pickECHConfig(echConfigs)
|
||||
if echConfig == nil {
|
||||
return nil, nil, nil, errors.New("tls: EncryptedClientHelloConfigList contains no valid configs")
|
||||
}
|
||||
ech = &echClientContext{config: echConfig}
|
||||
ech = &echClientContext{config: echConfig, kdfID: kdf.ID(), aeadID: aead.ID()}
|
||||
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
|
||||
@@ -225,17 +197,8 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCli
|
||||
hello.secureRenegotiationSupported = false
|
||||
hello.extendedMasterSecret = false
|
||||
|
||||
echPK, err := hpke.ParseHPKEPublicKey(ech.config.KemID, ech.config.PublicKey)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
suite, err := pickECHCipherSuite(ech.config.SymmetricCipherSuite)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
ech.kdfID, ech.aeadID = suite.KDFID, suite.AEADID
|
||||
info := append([]byte("tls ech\x00"), ech.config.raw...)
|
||||
ech.encapsulatedKey, ech.hpkeContext, err = hpke.SetupSender(ech.config.KemID, suite.KDFID, suite.AEADID, echPK, info)
|
||||
ech.encapsulatedKey, ech.hpkeContext, err = hpke.NewSender(echPK, kdf, aead, info)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
@@ -270,7 +233,6 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.serverName = hello.serverName
|
||||
|
||||
session, earlySecret, binderKey, err := c.loadSession(hello)
|
||||
if err != nil {
|
||||
@@ -324,7 +286,11 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
if hello.earlyData {
|
||||
suite := cipherSuiteTLS13ByID(session.cipherSuite)
|
||||
transcript := suite.hash.New()
|
||||
if err := transcriptMsg(hello, transcript); err != nil {
|
||||
transcriptHello := hello
|
||||
if ech != nil {
|
||||
transcriptHello = ech.innerHello
|
||||
}
|
||||
if err := transcriptMsg(transcriptHello, transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
earlyTrafficSecret := earlySecret.ClientEarlyTrafficSecret(transcript)
|
||||
@@ -350,7 +316,7 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
// If we are negotiating a protocol version that's lower than what we
|
||||
// support, check for the server downgrade canaries.
|
||||
// See RFC 8446, Section 4.1.3.
|
||||
maxVers := c.config.maxSupportedVersion(roleClient)
|
||||
maxVers := c.config.maxSupportedVersion(roleClient, c.quic != nil)
|
||||
tls12Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS12
|
||||
tls11Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS11
|
||||
if maxVers == VersionTLS13 && c.vers <= VersionTLS12 && (tls12Downgrade || tls11Downgrade) ||
|
||||
@@ -433,9 +399,6 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
|
||||
// Check that the cached server certificate is not expired, and that it's
|
||||
// valid for the ServerName. This should be ensured by the cache key, but
|
||||
// protect the application from a faulty ClientSessionCache implementation.
|
||||
if c.config.time().After(session.peerCertificates[0].NotAfter) {
|
||||
// Expired certificate, delete the entry.
|
||||
c.config.ClientSessionCache.Put(cacheKey, nil)
|
||||
@@ -447,6 +410,18 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
if err := session.peerCertificates[0].VerifyHostname(c.config.ServerName); err != nil {
|
||||
// This should be ensured by the cache key, but protect the
|
||||
// application from a faulty ClientSessionCache implementation.
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
opts := x509.VerifyOptions{
|
||||
CurrentTime: c.config.time(),
|
||||
Roots: c.config.RootCAs,
|
||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
}
|
||||
if !anyValidVerifiedChain(session.verifiedChains, opts) {
|
||||
// No valid chains, delete the entry.
|
||||
c.config.ClientSessionCache.Put(cacheKey, nil)
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
}
|
||||
@@ -534,7 +509,7 @@ func (c *Conn) pickTLSVersion(serverHello *serverHelloMsg) error {
|
||||
peerVersion = serverHello.supportedVersion
|
||||
}
|
||||
|
||||
vers, ok := c.config.mutualVersion(roleClient, []uint16{peerVersion})
|
||||
vers, ok := c.config.mutualVersion(roleClient, c.quic != nil, []uint16{peerVersion})
|
||||
if !ok {
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
return fmt.Errorf("tls: server selected unsupported protocol version %x", peerVersion)
|
||||
@@ -725,8 +700,9 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return err
|
||||
}
|
||||
if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ {
|
||||
c.curveID = CurveID(binary.BigEndian.Uint16(skx.key[1:]))
|
||||
if keyAgreement, ok := keyAgreement.(*ecdheKeyAgreement); ok {
|
||||
c.curveID = keyAgreement.curveID
|
||||
c.peerSigAlg = keyAgreement.signatureAlgorithm
|
||||
}
|
||||
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
@@ -753,6 +729,10 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
}
|
||||
}
|
||||
|
||||
if chainToSend != nil {
|
||||
hs.c.localCertificate = chainToSend.Certificate
|
||||
}
|
||||
|
||||
shd, ok := msg.(*serverHelloDoneMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
@@ -807,37 +787,43 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
|
||||
}
|
||||
|
||||
var sigType uint8
|
||||
var sigHash crypto.Hash
|
||||
if c.vers >= VersionTLS12 {
|
||||
signatureAlgorithm, err := selectSignatureScheme(c.vers, chainToSend, certReq.supportedSignatureAlgorithms)
|
||||
if err != nil {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return err
|
||||
}
|
||||
sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
|
||||
sigType, sigHash, err := typeAndHashFromSignatureScheme(signatureAlgorithm)
|
||||
if err != nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
certVerify.hasSignatureAlgorithm = true
|
||||
certVerify.signatureAlgorithm = signatureAlgorithm
|
||||
if hs.finishedHash.buffer == nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return errors.New("tls: internal error: did not keep handshake transcript for TLS 1.2")
|
||||
}
|
||||
signOpts := crypto.SignerOpts(sigHash)
|
||||
if sigType == signatureRSAPSS {
|
||||
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
|
||||
}
|
||||
certVerify.signature, err = crypto.SignMessage(key, c.config.rand(), hs.finishedHash.buffer, signOpts)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(key.Public())
|
||||
sigType, sigHash, err := legacyTypeAndHashFromPublicKey(key.Public())
|
||||
if err != nil {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash)
|
||||
signOpts := crypto.SignerOpts(sigHash)
|
||||
if sigType == signatureRSAPSS {
|
||||
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
|
||||
}
|
||||
certVerify.signature, err = key.Sign(c.config.rand(), signed, signOpts)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
signed := hs.finishedHash.hashForClientCertificate(sigType)
|
||||
certVerify.signature, err = key.Sign(c.config.rand(), signed, sigHash)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(certVerify, &hs.finishedHash); err != nil {
|
||||
@@ -1175,9 +1161,19 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
|
||||
}
|
||||
}
|
||||
|
||||
if fips140tls.Required() && !isCertificateAllowedFIPS(certs[0]) {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
err := errors.New("server's certificate is not allowed in FIPS 140-3 mode")
|
||||
return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
|
||||
}
|
||||
|
||||
switch certs[0].PublicKey.(type) {
|
||||
case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
|
||||
break
|
||||
case *mldsa.PublicKey:
|
||||
if c.vers < VersionTLS13 {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server's certificate uses ML-DSA, which requires TLS 1.3")
|
||||
}
|
||||
default:
|
||||
c.sendAlert(alertUnsupportedCertificate)
|
||||
return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
|
||||
|
||||
Reference in New Issue
Block a user