package tls import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "fmt" "math/big" "net" "os" "time" ) // generateSelfSigned creates a self-signed certificate for the given IP, // saves it to disk, and returns the tls.Certificate. func generateSelfSigned(lanIP, certFile, keyFile string) (tls.Certificate, error) { key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return tls.Certificate{}, fmt.Errorf("generate key: %w", err) } serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) if err != nil { return tls.Certificate{}, fmt.Errorf("generate serial: %w", err) } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"VoicePaste"}, CommonName: "VoicePaste Local", }, NotBefore: time.Now(), NotAfter: time.Now().Add(365 * 24 * time.Hour), // 1 year KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP(lanIP)}, DNSNames: []string{"localhost"}, } certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) if err != nil { return tls.Certificate{}, fmt.Errorf("create certificate: %w", err) } // Save cert PEM certOut, err := os.Create(certFile) if err != nil { return tls.Certificate{}, fmt.Errorf("create cert file: %w", err) } defer certOut.Close() pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certDER}) // Save key PEM keyDER, err := x509.MarshalECPrivateKey(key) if err != nil { return tls.Certificate{}, fmt.Errorf("marshal key: %w", err) } keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { return tls.Certificate{}, fmt.Errorf("create key file: %w", err) } defer keyOut.Close() pem.Encode(keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyDER}) return tls.LoadX509KeyPair(certFile, keyFile) }