github.com/ergo-services/ergo@v1.999.224/lib/cert.go (about)

     1  package lib
     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  	"sync"
    15  	"time"
    16  )
    17  
    18  // GenerateSelfSignedCert
    19  func GenerateSelfSignedCert(org string, hosts ...string) (tls.Certificate, error) {
    20  	var cert = tls.Certificate{}
    21  	certPrivKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
    22  	if err != nil {
    23  		return cert, err
    24  	}
    25  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
    26  	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
    27  	if err != nil {
    28  		return cert, err
    29  	}
    30  
    31  	template := x509.Certificate{
    32  		SerialNumber: serialNumber,
    33  		Subject: pkix.Name{
    34  			Organization: []string{org},
    35  		},
    36  		NotBefore: time.Now(),
    37  		NotAfter:  time.Now().Add(time.Hour * 24 * 365),
    38  		IsCA:      true,
    39  
    40  		KeyUsage:              x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
    41  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    42  		BasicConstraintsValid: true,
    43  	}
    44  
    45  	for _, h := range hosts {
    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  	certBytes, err1 := x509.CreateCertificate(rand.Reader, &template, &template,
    54  		&certPrivKey.PublicKey, certPrivKey)
    55  	if err1 != nil {
    56  		return cert, err1
    57  	}
    58  
    59  	certPEM := new(bytes.Buffer)
    60  	pem.Encode(certPEM, &pem.Block{
    61  		Type:  "CERTIFICATE",
    62  		Bytes: certBytes,
    63  	})
    64  
    65  	certPrivKeyPEM := new(bytes.Buffer)
    66  	x509Encoded, _ := x509.MarshalECPrivateKey(certPrivKey)
    67  	pem.Encode(certPrivKeyPEM, &pem.Block{
    68  		Type:  "RSA PRIVATE KEY",
    69  		Bytes: x509Encoded,
    70  	})
    71  
    72  	return tls.X509KeyPair(certPEM.Bytes(), certPrivKeyPEM.Bytes())
    73  }
    74  
    75  type CertUpdater struct {
    76  	sync.RWMutex
    77  	cert *tls.Certificate
    78  }
    79  
    80  func CreateCertUpdater(cert tls.Certificate) *CertUpdater {
    81  	return &CertUpdater{
    82  		cert: &cert,
    83  	}
    84  }
    85  
    86  func (cu *CertUpdater) Update(cert tls.Certificate) {
    87  	cu.Lock()
    88  	defer cu.Unlock()
    89  
    90  	cu.cert = &cert
    91  }
    92  
    93  func (cu *CertUpdater) GetCertificateFunc() func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
    94  	return func(ch *tls.ClientHelloInfo) (*tls.Certificate, error) {
    95  		cu.RLock()
    96  		defer cu.RUnlock()
    97  		return cu.cert, nil
    98  	}
    99  }