github.com/webdestroya/awsmocker@v0.2.6/certstore.go (about)

     1  package awsmocker
     2  
     3  import (
     4  	"crypto/rand"
     5  	"crypto/rsa"
     6  	"crypto/tls"
     7  	"crypto/x509"
     8  	"crypto/x509/pkix"
     9  	"math"
    10  	"math/big"
    11  	"net"
    12  	"sync"
    13  	"time"
    14  )
    15  
    16  var (
    17  	globalCertStore *CertStorage
    18  
    19  	leafCertStart = time.Unix(time.Now().Unix()-2592000, 0) // 2592000  = 30 day
    20  	leafCertEnd   = time.Unix(time.Now().Unix()+31536000, 0)
    21  )
    22  
    23  type CertStorage struct {
    24  	certs sync.Map
    25  
    26  	mu sync.Mutex
    27  
    28  	nextSerial int64
    29  	privateKey *rsa.PrivateKey
    30  }
    31  
    32  func (tcs *CertStorage) Fetch(hostname string) *tls.Certificate {
    33  
    34  	icert, ok := tcs.certs.Load(hostname)
    35  	if ok {
    36  		cert := icert.(tls.Certificate)
    37  		return &cert
    38  	}
    39  
    40  	return tcs.generateCert(hostname)
    41  }
    42  
    43  func (tcs *CertStorage) generateCert(hostname string) *tls.Certificate {
    44  
    45  	tcs.mu.Lock()
    46  	defer tcs.mu.Unlock()
    47  
    48  	tcs.nextSerial += 1
    49  
    50  	caCert := CACert()
    51  
    52  	template := x509.Certificate{
    53  		SerialNumber: big.NewInt(tcs.nextSerial),
    54  		Issuer:       caCert.Subject,
    55  		Subject: pkix.Name{
    56  			Country:            []string{"US"},
    57  			Organization:       []string{"webdestroya"},
    58  			OrganizationalUnit: []string{"awsmocker fake leaf"},
    59  		},
    60  		NotBefore: leafCertStart,
    61  		NotAfter:  leafCertEnd,
    62  
    63  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
    64  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    65  		BasicConstraintsValid: true,
    66  	}
    67  
    68  	if ip := net.ParseIP(hostname); ip != nil {
    69  		template.IPAddresses = append(template.IPAddresses, ip)
    70  	} else {
    71  		template.DNSNames = append(template.DNSNames, hostname)
    72  		template.Subject.CommonName = hostname
    73  	}
    74  
    75  	var derBytes []byte
    76  	var err error
    77  	if derBytes, err = x509.CreateCertificate(rand.Reader, &template, caCert, tcs.privateKey.Public(), caKeyPair.PrivateKey); err != nil {
    78  		panic("could not generate cert")
    79  	}
    80  	newCert := tls.Certificate{
    81  		Certificate: [][]byte{derBytes, caKeyPair.Certificate[0]},
    82  		PrivateKey:  tcs.privateKey,
    83  	}
    84  
    85  	val, _ := tcs.certs.LoadOrStore(hostname, newCert)
    86  
    87  	val2 := (val).(tls.Certificate)
    88  	return &val2
    89  }
    90  
    91  func init() {
    92  	privKey, _ := rsa.GenerateKey(rand.Reader, 2048)
    93  	startSerial, _ := rand.Int(rand.Reader, big.NewInt(int64(math.Pow(2, 40))))
    94  
    95  	globalCertStore = &CertStorage{
    96  		certs:      sync.Map{},
    97  		privateKey: privKey,
    98  		nextSerial: startSerial.Int64(),
    99  	}
   100  }