github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/internal/tls/tls.go (about)

     1  package tls
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"crypto/elliptic"
     7  	"crypto/rand"
     8  	"crypto/tls"
     9  	"crypto/x509"
    10  	"crypto/x509/pkix"
    11  	"encoding/pem"
    12  	"math/big"
    13  	"net"
    14  	"time"
    15  )
    16  
    17  func Certificate(host ...string) (tls.Certificate, error) {
    18  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    19  	if err != nil {
    20  		return tls.Certificate{}, err
    21  	}
    22  
    23  	notBefore := time.Now()
    24  	notAfter := notBefore.Add(time.Hour * 24 * 365)
    25  
    26  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
    27  	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
    28  	if err != nil {
    29  		return tls.Certificate{}, err
    30  	}
    31  
    32  	template := x509.Certificate{
    33  		SerialNumber: serialNumber,
    34  		Subject: pkix.Name{
    35  			Organization: []string{"Acme Co"},
    36  		},
    37  		NotBefore: notBefore,
    38  		NotAfter:  notAfter,
    39  
    40  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
    41  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    42  		BasicConstraintsValid: true,
    43  	}
    44  
    45  	for _, h := range host {
    46  		if ip := net.ParseIP(h); ip != nil {
    47  			template.IPAddresses = append(template.IPAddresses, ip)
    48  		} else {
    49  			template.DNSNames = append(template.DNSNames, h)
    50  		}
    51  	}
    52  
    53  	template.IsCA = true
    54  	template.KeyUsage |= x509.KeyUsageCertSign
    55  
    56  	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
    57  	if err != nil {
    58  		return tls.Certificate{}, err
    59  	}
    60  
    61  	// create public key
    62  	certOut := bytes.NewBuffer(nil)
    63  	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
    64  
    65  	// create private key
    66  	keyOut := bytes.NewBuffer(nil)
    67  	b, err := x509.MarshalECPrivateKey(priv)
    68  	if err != nil {
    69  		return tls.Certificate{}, err
    70  	}
    71  	pem.Encode(keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: b})
    72  
    73  	return tls.X509KeyPair(certOut.Bytes(), keyOut.Bytes())
    74  }