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 }