mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-07-25 11:24:15 +00:00
REALITY protocol: Add optional Post-Quantum ML-DSA-65 verification for cert's ExtraExtensions
4eaf7927f3
This commit is contained in:
parent
eed05549fc
commit
c9a3859495
9 changed files with 222 additions and 107 deletions
|
@ -23,6 +23,7 @@ import (
|
|||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/cloudflare/circl/sign/mldsa/mldsa65"
|
||||
utls "github.com/refraction-networking/utls"
|
||||
"github.com/xtls/reality"
|
||||
"github.com/xtls/xray-core/common/crypto"
|
||||
|
@ -56,6 +57,7 @@ func Server(c net.Conn, config *reality.Config) (net.Conn, error) {
|
|||
|
||||
type UConn struct {
|
||||
*utls.UConn
|
||||
Config *Config
|
||||
ServerName string
|
||||
AuthKey []byte
|
||||
Verified bool
|
||||
|
@ -73,14 +75,31 @@ func (c *UConn) HandshakeAddress() net.Address {
|
|||
}
|
||||
|
||||
func (c *UConn) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
if c.Config.Show {
|
||||
localAddr := c.LocalAddr().String()
|
||||
fmt.Printf("REALITY localAddr: %v\tis using X25519MLKEM768 for TLS' communication: %v\n", localAddr, c.HandshakeState.ServerHello.SelectedGroup == utls.X25519MLKEM768)
|
||||
fmt.Printf("REALITY localAddr: %v\tis using ML-DSA-65 for cert's extra verification: %v\n", localAddr, len(c.Config.Mldsa65Verify) > 0)
|
||||
}
|
||||
p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")
|
||||
certs := *(*([]*x509.Certificate))(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + p.Offset))
|
||||
if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok {
|
||||
h := hmac.New(sha512.New, c.AuthKey)
|
||||
h.Write(pub)
|
||||
if bytes.Equal(h.Sum(nil), certs[0].Signature) {
|
||||
c.Verified = true
|
||||
return nil
|
||||
if len(c.Config.Mldsa65Verify) > 0 {
|
||||
if len(certs[0].Extensions) > 0 {
|
||||
h.Write(c.HandshakeState.Hello.Raw)
|
||||
h.Write(c.HandshakeState.ServerHello.Raw)
|
||||
verify, _ := mldsa65.Scheme().UnmarshalBinaryPublicKey(c.Config.Mldsa65Verify)
|
||||
if mldsa65.Verify(verify.(*mldsa65.PublicKey), h.Sum(nil), nil, certs[0].Extensions[0].Value) {
|
||||
c.Verified = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
c.Verified = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
opts := x509.VerifyOptions{
|
||||
|
@ -98,7 +117,9 @@ func (c *UConn) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x50
|
|||
|
||||
func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destination) (net.Conn, error) {
|
||||
localAddr := c.LocalAddr().String()
|
||||
uConn := &UConn{}
|
||||
uConn := &UConn{
|
||||
Config: config,
|
||||
}
|
||||
utlsConfig := &utls.Config{
|
||||
VerifyPeerCertificate: uConn.VerifyPeerCertificate,
|
||||
ServerName: config.ServerName,
|
||||
|
@ -127,16 +148,20 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||
binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
|
||||
copy(hello.SessionId[8:], config.ShortId)
|
||||
if config.Show {
|
||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\thello.SessionId[:16]: %v\n", localAddr, hello.SessionId[:16]))
|
||||
fmt.Printf("REALITY localAddr: %v\thello.SessionId[:16]: %v\n", localAddr, hello.SessionId[:16])
|
||||
}
|
||||
publicKey, err := ecdh.X25519().NewPublicKey(config.PublicKey)
|
||||
if err != nil {
|
||||
return nil, errors.New("REALITY: publicKey == nil")
|
||||
}
|
||||
if uConn.HandshakeState.State13.KeyShareKeys.Ecdhe == nil {
|
||||
ecdhe := uConn.HandshakeState.State13.KeyShareKeys.Ecdhe
|
||||
if ecdhe == nil {
|
||||
ecdhe = uConn.HandshakeState.State13.KeyShareKeys.MlkemEcdhe
|
||||
}
|
||||
if ecdhe == nil {
|
||||
return nil, errors.New("Current fingerprint ", uConn.ClientHelloID.Client, uConn.ClientHelloID.Version, " does not support TLS 1.3, REALITY handshake cannot establish.")
|
||||
}
|
||||
uConn.AuthKey, _ = uConn.HandshakeState.State13.KeyShareKeys.Ecdhe.ECDH(publicKey)
|
||||
uConn.AuthKey, _ = ecdhe.ECDH(publicKey)
|
||||
if uConn.AuthKey == nil {
|
||||
return nil, errors.New("REALITY: SharedKey == nil")
|
||||
}
|
||||
|
@ -146,7 +171,7 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||
block, _ := aes.NewCipher(uConn.AuthKey)
|
||||
aead, _ := cipher.NewGCM(block)
|
||||
if config.Show {
|
||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tuConn.AuthKey[:16]: %v\tAEAD: %T\n", localAddr, uConn.AuthKey[:16], aead))
|
||||
fmt.Printf("REALITY localAddr: %v\tuConn.AuthKey[:16]: %v\tAEAD: %T\n", localAddr, uConn.AuthKey[:16], aead)
|
||||
}
|
||||
aead.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw)
|
||||
copy(hello.Raw[39:], hello.SessionId)
|
||||
|
@ -155,14 +180,14 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||
return nil, err
|
||||
}
|
||||
if config.Show {
|
||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tuConn.Verified: %v\n", localAddr, uConn.Verified))
|
||||
fmt.Printf("REALITY localAddr: %v\tuConn.Verified: %v\n", localAddr, uConn.Verified)
|
||||
}
|
||||
if !uConn.Verified {
|
||||
go func() {
|
||||
client := &http.Client{
|
||||
Transport: &http2.Transport{
|
||||
DialTLSContext: func(ctx context.Context, network, addr string, cfg *gotls.Config) (net.Conn, error) {
|
||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tDialTLSContext\n", localAddr))
|
||||
fmt.Printf("REALITY localAddr: %v\tDialTLSContext\n", localAddr)
|
||||
return uConn, nil
|
||||
},
|
||||
},
|
||||
|
@ -199,7 +224,7 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||
}
|
||||
req.Header.Set("User-Agent", fingerprint.Client) // TODO: User-Agent map
|
||||
if first && config.Show {
|
||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\treq.UserAgent(): %v\n", localAddr, req.UserAgent()))
|
||||
fmt.Printf("REALITY localAddr: %v\treq.UserAgent(): %v\n", localAddr, req.UserAgent())
|
||||
}
|
||||
times := 1
|
||||
if !first {
|
||||
|
@ -227,9 +252,9 @@ func UClient(c net.Conn, config *Config, ctx context.Context, dest net.Destinati
|
|||
}
|
||||
req.URL.Path = getPathLocked(paths)
|
||||
if config.Show {
|
||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\treq.Referer(): %v\n", localAddr, req.Referer()))
|
||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tlen(body): %v\n", localAddr, len(body)))
|
||||
errors.LogInfo(ctx, fmt.Sprintf("REALITY localAddr: %v\tlen(paths): %v\n", localAddr, len(paths)))
|
||||
fmt.Printf("REALITY localAddr: %v\treq.Referer(): %v\n", localAddr, req.Referer())
|
||||
fmt.Printf("REALITY localAddr: %v\tlen(body): %v\n", localAddr, len(body))
|
||||
fmt.Printf("REALITY localAddr: %v\tlen(paths): %v\n", localAddr, len(paths))
|
||||
}
|
||||
maps.Unlock()
|
||||
if !first {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue