// Package quicutil provides convenience functions that generate self-signed // certificates for QUIC connections that don't require PKI, such as trusted // connections over a local network, or connections where a different // verification mechanism is used. // // Do not use this for applications where PKI is needed, such as for public // websites! package quicutil import ( "context" "crypto/ed25519" "crypto/rand" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "math/big" "net" "time" "github.com/quic-go/quic-go" ) // Listen generates a new self-signed certificate and then listens // for QUIC connections on a given net.PacketConn. func Listen(conn net.PacketConn, config *quic.Config) (*quic.Listener, error) { tlsConf, err := GenerateSelfSignedCert() if err != nil { return nil, err } return quic.Listen(conn, tlsConf, config) } // ListenAddr generates a new self-signed certificate and then listens // for QUIC connections on a given address. func ListenAddr(addr string, config *quic.Config) (*quic.Listener, error) { tlsConf, err := GenerateSelfSignedCert() if err != nil { return nil, err } return quic.ListenAddr(addr, tlsConf, config) } // DialAddr establishes a new insecure QUIC connection to a server using a net.PacketConn. func Dial(ctx context.Context, conn net.PacketConn, addr net.Addr, config *quic.Config) (quic.Connection, error) { return quic.Dial(ctx, conn, addr, &tls.Config{InsecureSkipVerify: true}, config) } // DialAddr establishes a new insecure QUIC connection to a server. func DialAddr(ctx context.Context, addr string, config *quic.Config) (quic.Connection, error) { return quic.DialAddr(ctx, addr, &tls.Config{InsecureSkipVerify: true}, config) } // GenerateSelfSignedCert generates a new self-signed Ed25519 TLS certificate. func GenerateSelfSignedCert() (*tls.Config, error) { // Generate a new Ed25519 key pubkey, privkey, err := ed25519.GenerateKey(rand.Reader) if err != nil { return nil, err } // Generate a self-signed certificate template certTemplate := x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ Organization: []string{"Self-Signed Certificate"}, }, NotBefore: time.Now(), NotAfter: time.Date(9999, time.December, 31, 23, 59, 0, 0, time.UTC), // Valid until 31 December 9999 23:59 UTC KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } // Generate the certificate certDER, err := x509.CreateCertificate(rand.Reader, &certTemplate, &certTemplate, pubkey, privkey) if err != nil { return nil, err } // Convert private key to PKCS #8 form keyData, err := x509.MarshalPKCS8PrivateKey(privkey) if err != nil { return nil, err } // Create PEM-encoded certificate and private key blocks certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) keyPEM := pem.EncodeToMemory(&pem.Block{Type: "ED25519 PRIVATE KEY", Bytes: keyData}) // Create a new TLS certificate and key pair from the PEM-encoded data tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) if err != nil { return nil, err } // Create and configure a TLS config tlsConfig := &tls.Config{ Certificates: []tls.Certificate{tlsCert}, } return tlsConfig, nil }