Skip to content

Feature request: using TLS, instead of FakeTLS in tls:// and wss:// #1333

@Orbit173

Description

@Orbit173

I know that Yggdrasil uses E2E data encryption, but as an additional layer in tls:// and wss:// schemes, FakeTLS 1.3 encryption is used to hide metadata.
FakeTLS means that a temporary certificate is generated each time Yggdrasil is launched. The validity of this certificate is not verified by Ygg clients. This allows for a MiTM attack.

src/core/tls.go

func (c *Core) generateTLSConfig(cert *tls.Certificate) (*tls.Config, error) {
	config := &tls.Config{
		Certificates: []tls.Certificate{*cert},
		ClientAuth:   tls.NoClientCert,
		GetClientCertificate: func(cri *tls.CertificateRequestInfo) (*tls.Certificate, error) {
			return cert, nil
		},
		VerifyPeerCertificate: c.verifyTLSCertificate,
		VerifyConnection:      c.verifyTLSConnection,
		InsecureSkipVerify:    true,
		MinVersion:            tls.VersionTLS13,
	}
	return config, nil
}

func (c *Core) verifyTLSCertificate(_ [][]byte, _ [][]*x509.Certificate) error {
	return nil
}

func (c *Core) verifyTLSConnection(_ tls.ConnectionState) error {
	return nil
}

src/core/link_tls.go

type linkTLS struct {
	phony.Inbox
	*links
	tcp      *linkTCP
	listener *net.ListenConfig
	config   *tls.Config
}

func (l *links) newLinkTLS(tcp *linkTCP) *linkTLS {
	lt := &linkTLS{
		links: l,
		tcp:   tcp,
		listener: &net.ListenConfig{
			Control:   tcp.tcpContext,
			KeepAlive: -1,
		},
		config: l.core.config.tls.Clone(),
	}
	return lt
}

A simple example of MiTM using SSLproxy tool:
10.4.4.6 (Client) , 10.4.4.10/10.5.5.10 - gateway (Attacker) and 10.5.5.5 (Server)

Starting main event loop.
SNI peek: [n/a] [complete], fd=31
Connecting to [10.5.5.5]:443
===> Original server certificate:
Subject DN: /C=YG/CN=0c1776253aaeb16cf4c4651e031addfe3f2b5db26f82fb43ebd5990b2dd357ae
Common Names: 0c1776253aaeb16cf4c4651e031addfe3f2b5db26f82fb43ebd5990b2dd357ae
Fingerprint: D7:FF:54:E6:1A:6C:CD:F3:29:87E1:8B:D4:17:DA:D7:0A:C9:6C:01
Certificate cache: MISS
===> Forged server certificate:
Subject DN: /C=YG/CN=0c1776253aaeb16cf4c4651e031addfe3f2b5db26f82fb43ebd5990b2dd357ae
Common Names: 0c1776253aaeb16cf4c4651e031addfe3f2b5db26f82fb43ebd5990b2dd357ae
Fingerprint: 9C:E5:0A:52:FC:6E:82:B2:05:7E42:D0:F2:F6:EF:67:E5:91:CA:39
CONN: ssl 10.4.4.6 37756 10.5.5.5 443 sni:- names:0c1776253aaeb16cf4c4651e031addfe3f2b5db26f82fb43ebd5990b2dd357ae sproto:TLSv1.3:TLS_AES_128_GCM_SHA256 dproto:TLSv1.3:TLS_AES_128_GCM_SHA256 origcrt:D7FF54E61A6CCDF32987E18BD417DAD70AC96C01 usedcrt:9CE50A52FC6E82B2057E42D0F2F6EF67E591CA39 user:-
SSL connected to [10.5.5.5]:443 TLSv1.3 TLS_AES_128_GCM_SHA256
CLIENT_RANDOM 59B962A56443027ED25643AF713B1B0A20C6F1555F75B8ECD6DA0B9D83533384 70995292118DA3214E7E11ECCBB4E53F9742DBD32762869458E838F71999DE9800000000000000000000000000000000
SSL_free() in state 00000001 = 0001 = SSLOK (SSL negotiation finished successfully) [connect socket]
SSL_free() in state 00000001 = 0001 = SSLOK (SSL negotiation finished successfully) [accept socket]

Inside TLS

Image

Handshake

Image

My suggestions:

  1. Add a path to certificate in yggdrasil.conf
  2. Add the key -tlshash when adding a peer (tls/wss), and make it mandatory.
  3. Compare -tlshash and server certificate hash, if not match - reject the connection.
  4. Hash output in server logs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions