mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2024-12-22 16:07:31 +00:00
Remove TLS root validation
This is just too complicated compared to the per-peer/per-listener/per-interface password approach.
This commit is contained in:
parent
6dc847de31
commit
45b773eade
@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
@ -45,8 +44,6 @@ func main() {
|
||||
useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path")
|
||||
normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised")
|
||||
exportkey := flag.Bool("exportkey", false, "use in combination with either -useconf or -useconffile, outputs your private key in PEM format")
|
||||
exportcsr := flag.Bool("exportcsr", false, "use in combination with either -useconf or -useconffile, outputs your self-signed certificate request in PEM format")
|
||||
exportcert := flag.Bool("exportcert", false, "use in combination with either -useconf or -useconffile, outputs your self-signed certificate in PEM format")
|
||||
confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON")
|
||||
autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)")
|
||||
ver := flag.Bool("version", false, "prints the version of this build")
|
||||
@ -177,30 +174,10 @@ func main() {
|
||||
}
|
||||
fmt.Println(string(pem))
|
||||
return
|
||||
|
||||
case *exportcsr:
|
||||
pem, err := cfg.GenerateCertificateSigningRequest()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(pem))
|
||||
return
|
||||
|
||||
case *exportcert:
|
||||
pem, err := cfg.MarshalPEMCertificate()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(pem))
|
||||
return
|
||||
}
|
||||
|
||||
n := &node{}
|
||||
|
||||
// Track certificate fingerprints for configured roots, so
|
||||
// that we can match them using the multicast discriminator.
|
||||
fingerprints := map[[20]byte]struct{}{}
|
||||
|
||||
// Setup the Yggdrasil node itself.
|
||||
{
|
||||
options := []core.SetupOption{
|
||||
@ -218,10 +195,6 @@ func main() {
|
||||
options = append(options, core.Peer{URI: peer, SourceInterface: intf})
|
||||
}
|
||||
}
|
||||
for _, root := range cfg.RootCertificates {
|
||||
options = append(options, core.RootCertificate(*root))
|
||||
fingerprints[sha1.Sum(root.Raw[:])] = struct{}{}
|
||||
}
|
||||
for _, allowed := range cfg.AllowedPublicKeys {
|
||||
k, err := hex.DecodeString(allowed)
|
||||
if err != nil {
|
||||
@ -259,29 +232,6 @@ func main() {
|
||||
Priority: uint8(intf.Priority),
|
||||
})
|
||||
}
|
||||
if len(fingerprints) > 0 {
|
||||
var matcher multicast.DiscriminatorMatch = func(b []byte) bool {
|
||||
// Break apart the discriminator into 20-byte chunks and
|
||||
// see whether any of them match the configured root CA
|
||||
// fingerprints. If any of them match, we'll return true.
|
||||
var f [20]byte
|
||||
for len(b) >= len(f) {
|
||||
b = b[copy(f[:], b):]
|
||||
if _, ok := fingerprints[f]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
// Populate our own discriminator with the fingerprints of our
|
||||
// configured root CAs.
|
||||
var discriminator multicast.Discriminator
|
||||
for f := range fingerprints {
|
||||
discriminator = append(discriminator, f[:]...)
|
||||
}
|
||||
options = append(options, matcher)
|
||||
options = append(options, discriminator)
|
||||
}
|
||||
if n.multicast, err = multicast.New(n.core, logger, options...); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -70,9 +70,6 @@ func (m *Yggdrasil) StartJSON(configjson []byte) error {
|
||||
}
|
||||
options = append(options, core.AllowedPublicKey(k[:]))
|
||||
}
|
||||
for _, root := range m.config.RootCertificates {
|
||||
options = append(options, core.RootCertificate(*root))
|
||||
}
|
||||
var err error
|
||||
m.core, err = core.New(m.config.Certificate, logger, options...)
|
||||
if err != nil {
|
||||
|
@ -43,9 +43,6 @@ type NodeConfig struct {
|
||||
PrivateKey KeyBytes `comment:"Your private key. DO NOT share this with anyone!"`
|
||||
PrivateKeyPath string `json:",omitempty"`
|
||||
Certificate *tls.Certificate `json:"-"`
|
||||
CertificatePath string `json:",omitempty"`
|
||||
RootCertificates []*x509.Certificate `json:"-"`
|
||||
RootCertificatePaths []string `json:",omitempty"`
|
||||
Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tls://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."`
|
||||
InterfacePeers map[string][]string `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ \"tls://a.b.c.d:e\" ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."`
|
||||
Listen []string `comment:"Listen addresses for incoming connections. You will need to add\nlisteners in order to accept incoming peerings from non-local nodes.\nMulticast peer discovery will work regardless of any listeners set\nhere. Each listener should be specified in URI format as above, e.g.\ntls://0.0.0.0:0 or tls://[::]:0 to listen on all interfaces."`
|
||||
@ -138,19 +135,6 @@ func (cfg *NodeConfig) postprocessConfig() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if cfg.CertificatePath != "" {
|
||||
if cfg.PrivateKeyPath == "" {
|
||||
return fmt.Errorf("CertificatePath requires PrivateKeyPath")
|
||||
}
|
||||
cfg.Certificate = nil
|
||||
f, err := os.ReadFile(cfg.CertificatePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cfg.UnmarshalPEMCertificate(f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case cfg.Certificate == nil:
|
||||
// No self-signed certificate has been generated yet.
|
||||
@ -163,35 +147,6 @@ func (cfg *NodeConfig) postprocessConfig() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cfg.RootCertificates = cfg.RootCertificates[:0]
|
||||
for _, path := range cfg.RootCertificatePaths {
|
||||
f, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cfg.UnmarshalRootCertificate(f); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *NodeConfig) UnmarshalRootCertificate(b []byte) error {
|
||||
p, _ := pem.Decode(b)
|
||||
if p == nil {
|
||||
return fmt.Errorf("failed to parse PEM file")
|
||||
}
|
||||
if p.Type != "CERTIFICATE" {
|
||||
return fmt.Errorf("unexpected PEM type %q", p.Type)
|
||||
}
|
||||
cert, err := x509.ParseCertificate(p.Bytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load X.509 keypair: %w", err)
|
||||
}
|
||||
if !cert.IsCA {
|
||||
return fmt.Errorf("supplied root certificate is not a certificate authority")
|
||||
}
|
||||
cfg.RootCertificates = append(cfg.RootCertificates, cert)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -215,26 +170,6 @@ func (cfg *NodeConfig) GenerateSelfSignedCertificate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *NodeConfig) GenerateCertificateSigningRequest() ([]byte, error) {
|
||||
template := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: hex.EncodeToString(cfg.PrivateKey),
|
||||
},
|
||||
SignatureAlgorithm: x509.PureEd25519,
|
||||
}
|
||||
|
||||
csrBytes, err := x509.CreateCertificateRequest(rand.Reader, template, ed25519.PrivateKey(cfg.PrivateKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pemBytes := bytes.NewBuffer(nil)
|
||||
if err := pem.Encode(pemBytes, &pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pemBytes.Bytes(), nil
|
||||
}
|
||||
|
||||
func (cfg *NodeConfig) MarshalPEMCertificate() ([]byte, error) {
|
||||
privateKey := ed25519.PrivateKey(cfg.PrivateKey)
|
||||
publicKey := privateKey.Public().(ed25519.PublicKey)
|
||||
@ -263,15 +198,6 @@ func (cfg *NodeConfig) MarshalPEMCertificate() ([]byte, error) {
|
||||
return pem.EncodeToMemory(block), nil
|
||||
}
|
||||
|
||||
func (cfg *NodeConfig) UnmarshalPEMCertificate(b []byte) error {
|
||||
tlsCert, err := tls.LoadX509KeyPair(cfg.CertificatePath, cfg.PrivateKeyPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load X.509 keypair: %w", err)
|
||||
}
|
||||
cfg.Certificate = &tlsCert
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *NodeConfig) NewPrivateKey() {
|
||||
_, spriv, err := ed25519.GenerateKey(nil)
|
||||
if err != nil {
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -40,7 +39,6 @@ type Core struct {
|
||||
addPeerTimer *time.Timer
|
||||
config struct {
|
||||
tls *tls.Config // immutable after startup
|
||||
roots *x509.CertPool // immutable after startup
|
||||
//_peers map[Peer]*linkInfo // configurable after startup
|
||||
_listeners map[ListenAddress]struct{} // configurable after startup
|
||||
nodeinfo NodeInfo // immutable after startup
|
||||
@ -110,9 +108,6 @@ func New(cert *tls.Certificate, logger Logger, opts ...SetupOption) (*Core, erro
|
||||
c.log.Infof("Your public key is %s", hex.EncodeToString(c.public))
|
||||
c.log.Infof("Your IPv6 address is %s", address.String())
|
||||
c.log.Infof("Your IPv6 subnet is %s", subnet.String())
|
||||
if c.config.roots != nil {
|
||||
c.log.Println("Yggdrasil is running in TLS-only mode")
|
||||
}
|
||||
c.proto.init(c)
|
||||
if err := c.links.init(c); err != nil {
|
||||
return nil, fmt.Errorf("error initialising links: %w", err)
|
||||
@ -169,10 +164,6 @@ func (c *Core) _close() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Core) isTLSOnly() bool {
|
||||
return c.config.roots != nil
|
||||
}
|
||||
|
||||
func (c *Core) MTU() uint64 {
|
||||
const sessionTypeOverhead = 1
|
||||
MTU := c.PacketConn.MTU() - sessionTypeOverhead
|
||||
|
@ -69,9 +69,6 @@ func (l *linkTCP) dialersFor(url *url.URL, info linkInfo) ([]*tcpDialer, error)
|
||||
}
|
||||
|
||||
func (l *linkTCP) dial(ctx context.Context, url *url.URL, info linkInfo, options linkOptions) (net.Conn, error) {
|
||||
if l.core.isTLSOnly() {
|
||||
return nil, fmt.Errorf("TCP peer prohibited in TLS-only mode")
|
||||
}
|
||||
dialers, err := l.dialersFor(url, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -92,9 +89,6 @@ func (l *linkTCP) dial(ctx context.Context, url *url.URL, info linkInfo, options
|
||||
}
|
||||
|
||||
func (l *linkTCP) listen(ctx context.Context, url *url.URL, sintf string) (net.Listener, error) {
|
||||
if l.core.isTLSOnly() {
|
||||
return nil, fmt.Errorf("TCP listener prohibited in TLS-only mode")
|
||||
}
|
||||
hostport := url.Host
|
||||
if sintf != "" {
|
||||
if host, port, err := net.SplitHostPort(hostport); err == nil {
|
||||
|
@ -2,19 +2,12 @@ package core
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func (c *Core) _applyOption(opt SetupOption) (err error) {
|
||||
switch v := opt.(type) {
|
||||
case RootCertificate:
|
||||
cert := x509.Certificate(v)
|
||||
if c.config.roots == nil {
|
||||
c.config.roots = x509.NewCertPool()
|
||||
}
|
||||
c.config.roots.AddCert(&cert)
|
||||
case Peer:
|
||||
u, err := url.Parse(v.URI)
|
||||
if err != nil {
|
||||
@ -39,7 +32,6 @@ type SetupOption interface {
|
||||
isSetupOption()
|
||||
}
|
||||
|
||||
type RootCertificate x509.Certificate
|
||||
type ListenAddress string
|
||||
type Peer struct {
|
||||
URI string
|
||||
@ -49,7 +41,6 @@ type NodeInfo map[string]interface{}
|
||||
type NodeInfoPrivacy bool
|
||||
type AllowedPublicKey ed25519.PublicKey
|
||||
|
||||
func (a RootCertificate) isSetupOption() {}
|
||||
func (a ListenAddress) isSetupOption() {}
|
||||
func (a Peer) isSetupOption() {}
|
||||
func (a NodeInfo) isSetupOption() {}
|
||||
|
@ -17,39 +17,20 @@ func (c *Core) generateTLSConfig(cert *tls.Certificate) (*tls.Config, error) {
|
||||
VerifyConnection: c.verifyTLSConnection,
|
||||
InsecureSkipVerify: true,
|
||||
MinVersion: tls.VersionTLS13,
|
||||
NextProtos: []string{"yggdrasil/0.5"},
|
||||
NextProtos: []string{
|
||||
fmt.Sprintf("yggdrasil/%d.%d", ProtocolVersionMajor, ProtocolVersionMinor),
|
||||
},
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (c *Core) verifyTLSCertificate(rawCerts [][]byte, _ [][]*x509.Certificate) error {
|
||||
if c.config.roots == nil {
|
||||
// If there's no certificate pool configured then we will
|
||||
// accept all TLS certificates.
|
||||
return nil
|
||||
}
|
||||
if len(rawCerts) == 0 {
|
||||
return fmt.Errorf("expected at least one certificate")
|
||||
}
|
||||
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: c.config.roots,
|
||||
}
|
||||
|
||||
for i, rawCert := range rawCerts {
|
||||
if i == 0 {
|
||||
// The first certificate is the leaf certificate. All other
|
||||
// certificates in the list are intermediates, so add them
|
||||
// into the VerifyOptions.
|
||||
continue
|
||||
}
|
||||
cert, err := x509.ParseCertificate(rawCert)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse intermediate certificate: %w", err)
|
||||
}
|
||||
opts.Intermediates.AddCert(cert)
|
||||
if len(rawCerts) != 1 {
|
||||
return fmt.Errorf("expected one certificate")
|
||||
}
|
||||
|
||||
/*
|
||||
opts := x509.VerifyOptions{}
|
||||
cert, err := x509.ParseCertificate(rawCerts[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse leaf certificate: %w", err)
|
||||
@ -57,6 +38,9 @@ func (c *Core) verifyTLSCertificate(rawCerts [][]byte, _ [][]*x509.Certificate)
|
||||
|
||||
_, err = cert.Verify(opts)
|
||||
return err
|
||||
*/
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Core) verifyTLSConnection(cs tls.ConnectionState) error {
|
||||
|
Loading…
x
Reference in New Issue
Block a user