| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 | package tlsimport (	"crypto/ed25519"	"crypto/rand"	"crypto/x509"	"crypto/x509/pkix"	"encoding/base64"	"encoding/pem"	"errors"	"fmt"	"math/big"	"os"	"time"	"filippo.io/edwards25519"	"golang.zx2c4.com/wireguard/wgctrl/wgtypes")// CERTTIFICAT_VALIDITY duration of certificate validity in daysconst CERTIFICATE_VALIDITY = 365type (	// Key is the struct for an edwards representation point	Key struct {		point *edwards25519.Point	})// NewKey generates a new key.func NewKey() *Key {	seed := make([]byte, 64)	rand.Reader.Read(seed)	s, _ := (&edwards25519.Scalar{}).SetUniformBytes(seed)	return &Key{(&edwards25519.Point{}).ScalarBaseMult(s)}}// Key.Ed25519PrivateKey returns the private key in Edwards form used for EdDSA.func (n *Key) Ed25519PrivateKey() (ed25519.PrivateKey, error) {	if n.point == nil {		return ed25519.PrivateKey{}, errors.New("nil point")	}	if len(n.point.Bytes()) != ed25519.SeedSize {		return ed25519.PrivateKey{}, errors.New("incorrect seed size")	}	return ed25519.NewKeyFromSeed(n.point.Bytes()), nil}// Key.Curve25519PrivateKey returns the private key in Montogomery form used for ECDH.func (n *Key) Curve25519PrivateKey() (wgtypes.Key, error) {	if n.point == nil {		return wgtypes.Key{}, errors.New("nil point")	}	if len(n.point.Bytes()) != ed25519.SeedSize {		return wgtypes.Key{}, errors.New("incorrect seed size")	}	return wgtypes.ParseKey(base64.StdEncoding.EncodeToString(n.point.BytesMontgomery()))}// Key.Save : saves the private key to path.func (n *Key) Save(path string) error {	f, err := os.Create(path)	if err != nil {		return err	}	defer f.Close()	f.Write(n.point.Bytes())	return nil}// ReadFrom reads a private key from path.func ReadFrom(path string) (*Key, error) {	key, err := os.ReadFile(path)	if err != nil {		return nil, err	}	point, err := (&edwards25519.Point{}).SetBytes(key)	if err != nil {		return nil, err	}	return &Key{point}, nil}// NewName creates a new pkix.Name with common name, country, and organizationfunc NewName(commonName, country, org string) pkix.Name {	res := NewCName(commonName)	res.Country = []string{country}	res.Organization = []string{org}	return res}// NewCName creates a new pkix.Name with only a common namefunc NewCName(commonName string) pkix.Name {	return pkix.Name{		CommonName: commonName,	}}// NewCSR creates a new certificate signing request for afunc NewCSR(key ed25519.PrivateKey, name pkix.Name) (*x509.CertificateRequest, error) {	dnsnames := []string{}	dnsnames = append(dnsnames, name.CommonName)	derCertRequest, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{		Subject:            name,		PublicKey:          key.Public(),		DNSNames:           dnsnames,		PublicKeyAlgorithm: x509.Ed25519,		Version:            3,	}, key)	if err != nil {		return nil, err	}	csr, err := x509.ParseCertificateRequest(derCertRequest)	if err != nil {		return nil, err	}	return csr, nil}// SelfSignedCA returns a new self-signed certificatefunc SelfSignedCA(key ed25519.PrivateKey, req *x509.CertificateRequest, days int) (*x509.Certificate, error) {	template := &x509.Certificate{		BasicConstraintsValid: true,		IsCA:                  true,		Version:               req.Version,		KeyUsage:              x509.KeyUsageCertSign | x509.KeyUsageCRLSign | x509.KeyUsageDataEncipherment,		NotAfter:              time.Now().Add(duration(days)),		NotBefore:             time.Now(),		SerialNumber:          serialNumber(),		PublicKey:             key.Public(),		Subject: pkix.Name{			CommonName:   req.Subject.CommonName,			Organization: req.Subject.Organization,			Country:      req.Subject.Country,		},	}	rootCa, err := x509.CreateCertificate(rand.Reader, template, template, req.PublicKey, key)	if err != nil {		return nil, err	}	result, err := x509.ParseCertificate(rootCa)	if err != nil {		return nil, err	}	return result, nil}// NewEndEntityCert issues a new certificate from a parent certificate authorityfunc NewEndEntityCert(key ed25519.PrivateKey, req *x509.CertificateRequest, parent *x509.Certificate, days int) (*x509.Certificate, error) {	template := &x509.Certificate{		Version:               req.Version,		NotBefore:             time.Now(),		NotAfter:              time.Now().Add(duration(days)),		SerialNumber:          serialNumber(),		Subject:               req.Subject,		Issuer:                parent.Subject,		KeyUsage:              x509.KeyUsageDigitalSignature,		BasicConstraintsValid: true,		DNSNames:              req.DNSNames,	}	rootCa, err := x509.CreateCertificate(rand.Reader, template, parent, req.PublicKey, key)	if err != nil {		return nil, err	}	result, err := x509.ParseCertificate(rootCa)	if err != nil {		return nil, err	}	return result, nil}// SaveRequest saves a certificate request to the specified pathfunc SaveRequest(path, name string, csr *x509.CertificateRequest) error {	if err := os.MkdirAll(path, 0600); err != nil {		return err	}	requestOut, err := os.Create(path + name)	if err != nil {		return err	}	defer requestOut.Close()	if err := pem.Encode(requestOut, &pem.Block{		Type:  "CERTIFICATE REQUEST",		Bytes: csr.Raw,	}); err != nil {		return err	}	return nil}// SaveCert save a certificate to the specified pathfunc SaveCert(path, name string, cert *x509.Certificate) error {	//certbytes, err := x509.ParseCertificate(cert)	if err := os.MkdirAll(path, 0600); err != nil {		return fmt.Errorf("failed to create dir %s %w", path, err)	}	certOut, err := os.Create(path + name)	if err != nil {		return fmt.Errorf("failed to open certficate file for writing: %v", err)	}	defer certOut.Close()	if err := pem.Encode(certOut, &pem.Block{		Type:  "CERTIFICATE",		Bytes: cert.Raw,	}); err != nil {		return fmt.Errorf("failed to write certificate to file %v", err)	}	return nil}// SaveKey save a private key (ed25519) to the specified pathfunc SaveKey(path, name string, key ed25519.PrivateKey) error {	//func SaveKey(name string, key *ecdsa.PrivateKey) error {	if err := os.MkdirAll(path, 0600); err != nil {		return fmt.Errorf("failed to create dir %s %w", path, err)	}	keyOut, err := os.Create(path + name)	if err != nil {		return fmt.Errorf("failed open key file for writing: %v", err)	}	defer keyOut.Close()	privBytes, err := x509.MarshalPKCS8PrivateKey(key)	if err != nil {		return fmt.Errorf("failedto marshal key %v ", err)	}	if err := pem.Encode(keyOut, &pem.Block{		Type:  "PRIVATE KEY",		Bytes: privBytes,	}); err != nil {		return fmt.Errorf("failed to write key to file %v", err)	}	return nil}// ReadCert reads a certificate from diskfunc ReadCert(name string) (*x509.Certificate, error) {	contents, err := os.ReadFile(name)	if err != nil {		return nil, fmt.Errorf("unable to read file %w", err)	}	block, _ := pem.Decode(contents)	if block == nil || block.Type != "CERTIFICATE" {		return nil, errors.New("not a cert " + block.Type)	}	cert, err := x509.ParseCertificate(block.Bytes)	if err != nil {		return nil, fmt.Errorf("unable to parse cert %w", err)	}	return cert, nil}// ReadKey reads a private key (ed25519) from diskfunc ReadKey(name string) (*ed25519.PrivateKey, error) {	bytes, err := os.ReadFile(name)	if err != nil {		return nil, fmt.Errorf("unable to read file %w", err)	}	keyBytes, _ := pem.Decode(bytes)	key, err := x509.ParsePKCS8PrivateKey(keyBytes.Bytes)	if err != nil {		return nil, fmt.Errorf("unable to parse file %w", err)	}	private := key.(ed25519.PrivateKey)	return &private, nil}// serialNumber generates a serial number for a certificatefunc serialNumber() *big.Int {	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)	if err != nil {		return nil	}	return serialNumber}// duration coverts the number of days to time.durationfunc duration(days int) time.Duration {	hours := days * 24	duration, err := time.ParseDuration(fmt.Sprintf("%dh", hours))	if err != nil {		duration = time.Until(time.Now().Add(time.Hour * 24))	}	return duration}
 |