@@ -38,17 +38,20 @@ import (
3838 aTLS "github.com/sagernet/sing/common/tls"
3939
4040 utls "github.com/metacubex/utls"
41+ "github.com/cloudflare/circl/sign/mldsa/mldsa65"
4142 "golang.org/x/crypto/hkdf"
4243 "golang.org/x/net/http2"
4344)
4445
4546var _ ConfigCompat = (* RealityClientConfig )(nil )
4647
4748type RealityClientConfig struct {
48- ctx context.Context
49- uClient * UTLSClientConfig
50- publicKey []byte
51- shortID [8 ]byte
49+ ctx context.Context
50+ logger logger.ContextLogger
51+ uClient * UTLSClientConfig
52+ publicKey []byte
53+ shortID [8 ]byte
54+ mldsa65Verify []byte
5255}
5356
5457func NewRealityClient (ctx context.Context , logger logger.ContextLogger , serverAddress string , options option.OutboundTLSOptions ) (Config , error ) {
@@ -84,7 +87,18 @@ func newRealityClient(ctx context.Context, logger logger.ContextLogger, serverAd
8487 return nil , E .New ("invalid short_id" )
8588 }
8689
87- var config Config = & RealityClientConfig {ctx , uClient .(* UTLSClientConfig ), publicKey , shortID }
90+ var mldsa65Verify []byte
91+ if options .Reality .Mldsa65Verify != "" {
92+ mldsa65Verify , err = base64 .RawURLEncoding .DecodeString (options .Reality .Mldsa65Verify )
93+ if err != nil {
94+ return nil , E .Cause (err , "decode mldsa65_verify" )
95+ }
96+ if len (mldsa65Verify ) != 1952 {
97+ return nil , E .New ("invalid mldsa65_verify" )
98+ }
99+ }
100+
101+ var config Config = & RealityClientConfig {ctx , logger , uClient .(* UTLSClientConfig ), publicKey , shortID , mldsa65Verify }
88102 if options .KernelRx || options .KernelTx {
89103 if ! C .IsLinux {
90104 return nil , E .New ("kTLS is only supported on Linux" )
@@ -133,7 +147,9 @@ func (e *RealityClientConfig) Client(conn net.Conn) (Conn, error) {
133147
134148func (e * RealityClientConfig ) ClientHandshake (ctx context.Context , conn net.Conn ) (aTLS.Conn , error ) {
135149 verifier := & realityVerifier {
136- serverName : e .uClient .ServerName (),
150+ serverName : e .uClient .ServerName (),
151+ mldsa65Verify : e .mldsa65Verify ,
152+ logger : e .logger ,
137153 }
138154 uConfig := e .uClient .config .Clone ()
139155 uConfig .InsecureSkipVerify = true
@@ -268,17 +284,21 @@ func realityClientFallback(ctx context.Context, uConn net.Conn, serverName strin
268284func (e * RealityClientConfig ) Clone () Config {
269285 return & RealityClientConfig {
270286 e .ctx ,
287+ e .logger ,
271288 e .uClient .Clone ().(* UTLSClientConfig ),
272289 e .publicKey ,
273290 e .shortID ,
291+ e .mldsa65Verify ,
274292 }
275293}
276294
277295type realityVerifier struct {
278296 * utls.UConn
279- serverName string
280- authKey []byte
281- verified bool
297+ serverName string
298+ authKey []byte
299+ verified bool
300+ mldsa65Verify []byte
301+ logger logger.ContextLogger
282302}
283303
284304func (c * realityVerifier ) VerifyPeerCertificate (rawCerts [][]byte , verifiedChains [][]* x509.Certificate ) error {
@@ -288,8 +308,46 @@ func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChain
288308 h := hmac .New (sha512 .New , c .authKey )
289309 h .Write (pub )
290310 if bytes .Equal (h .Sum (nil ), certs [0 ].Signature ) {
291- c .verified = true
292- return nil
311+ if len (c .mldsa65Verify ) > 0 {
312+ if c .logger != nil {
313+ c .logger .Trace ("REALITY: verifying certificate with ML-DSA-65" )
314+ }
315+ if debug .Enabled {
316+ fmt .Printf ("REALITY: verifying certificate with ML-DSA-65\n " )
317+ }
318+ if len (certs [0 ].Extensions ) > 0 {
319+ h .Write (c .HandshakeState .Hello .Raw )
320+ h .Write (c .HandshakeState .ServerHello .Raw )
321+ verify , err := mldsa65 .Scheme ().UnmarshalBinaryPublicKey (c .mldsa65Verify )
322+ if err != nil {
323+ if c .logger != nil {
324+ c .logger .Trace ("REALITY: failed to unmarshal ML-DSA-65 public key" )
325+ }
326+ return E .Cause (err , "unmarshal ML-DSA-65 public key" )
327+ }
328+ if mldsa65 .Verify (verify .(* mldsa65.PublicKey ), h .Sum (nil ), nil , certs [0 ].Extensions [0 ].Value ) {
329+ if c .logger != nil {
330+ c .logger .Trace ("REALITY: ML-DSA-65 verification succeeded" )
331+ }
332+ if debug .Enabled {
333+ fmt .Printf ("REALITY: ML-DSA-65 verification succeeded\n " )
334+ }
335+ c .verified = true
336+ return nil
337+ } else {
338+ if c .logger != nil {
339+ c .logger .Trace ("REALITY: ML-DSA-65 verification failed" )
340+ }
341+ }
342+ } else {
343+ if c .logger != nil {
344+ c .logger .Trace ("REALITY: certificate has no extensions for ML-DSA-65 signature" )
345+ }
346+ }
347+ } else {
348+ c .verified = true
349+ return nil
350+ }
293351 }
294352 }
295353 opts := x509.VerifyOptions {
0 commit comments