github.com/verrazzano/verrazzano-monitoring-operator@v0.0.30/test/integ/util/certs.go (about)

     1  // Copyright (C) 2020, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package util
     5  
     6  import (
     7  	"crypto/ecdsa"
     8  	"crypto/elliptic"
     9  	"crypto/rand"
    10  	"crypto/rsa"
    11  	"crypto/x509"
    12  	"crypto/x509/pkix"
    13  	"encoding/pem"
    14  	"fmt"
    15  	"math/big"
    16  	"net"
    17  	"os"
    18  	"strings"
    19  	"time"
    20  
    21  	"go.uber.org/zap"
    22  )
    23  
    24  func publicKey(priv interface{}) interface{} {
    25  	switch k := priv.(type) {
    26  	case *rsa.PrivateKey:
    27  		return &k.PublicKey
    28  	case *ecdsa.PrivateKey:
    29  		return &k.PublicKey
    30  	default:
    31  		return nil
    32  	}
    33  }
    34  
    35  func pemBlockForKey(priv interface{}) *pem.Block {
    36  	switch k := priv.(type) {
    37  	case *rsa.PrivateKey:
    38  		return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
    39  	case *ecdsa.PrivateKey:
    40  		b, err := x509.MarshalECPrivateKey(k)
    41  		if err != nil {
    42  			zap.S().Errorf("Unable to marshal ECDSA private key: %v", err)
    43  			return nil
    44  		}
    45  		return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
    46  	default:
    47  		return nil
    48  	}
    49  }
    50  
    51  // GenerateKeys this generates keys
    52  //
    53  //	host  	   : string "Comma-separated hostnames and IPs to generate a certificate for"
    54  //	validFrom  : string "Creation date formatted as Jan 1 15:04:05 2011"
    55  //	validFor   : time.Duration 365*24*time.Hour, "Duration that certificate is valid for"
    56  //	isCA       : bool "whether this cert should be its own Certificate Authority"
    57  //	rsaBits    : int "Size of RSA key to generate. Ignored if --ecdsa-curve is set"
    58  //	ecdsaCurve : string "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521")
    59  func GenerateKeys(host string, domain string, validFrom string, validFor time.Duration, isCA bool, rsaBits int, ecdsaCurve string) error {
    60  
    61  	if len(host) == 0 {
    62  		zap.S().Error("Missing required host argument")
    63  	}
    64  
    65  	var priv interface{}
    66  	var err error
    67  	switch ecdsaCurve {
    68  	case "":
    69  		priv, err = rsa.GenerateKey(rand.Reader, rsaBits)
    70  	case "P224":
    71  		priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
    72  	case "P256":
    73  		priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    74  	case "P384":
    75  		priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
    76  	case "P521":
    77  		priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
    78  	default:
    79  		zap.S().Errorf("Unrecognized elliptic curve: %q", ecdsaCurve)
    80  		return err
    81  	}
    82  	if err != nil {
    83  		zap.S().Errorf("failed to generate private key: %s", err)
    84  	}
    85  
    86  	var notBefore time.Time
    87  	if len(validFrom) == 0 {
    88  		notBefore = time.Now()
    89  	} else {
    90  		notBefore, err = time.Parse("Jan 2 15:04:05 2006", validFrom)
    91  		if err != nil {
    92  			zap.S().Errorf("Failed to parse creation date: %s\n", err)
    93  			return err
    94  		}
    95  	}
    96  
    97  	notAfter := notBefore.Add(validFor)
    98  
    99  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
   100  	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
   101  	if err != nil {
   102  		zap.S().Errorf("failed to generate serial number: %s", err)
   103  	}
   104  
   105  	template := x509.Certificate{
   106  		SerialNumber: serialNumber,
   107  		Subject: pkix.Name{
   108  			Country:            []string{"US"},
   109  			Locality:           []string{"Portland"},
   110  			Organization:       []string{"VMO"},
   111  			OrganizationalUnit: []string{"PDX"},
   112  			CommonName:         domain,
   113  		},
   114  		NotBefore: notBefore,
   115  		NotAfter:  notAfter,
   116  
   117  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   118  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   119  		BasicConstraintsValid: true,
   120  	}
   121  
   122  	hosts := strings.Split(host, ",")
   123  	for _, h := range hosts {
   124  		if ip := net.ParseIP(h); ip != nil {
   125  			template.IPAddresses = append(template.IPAddresses, ip)
   126  		} else {
   127  			template.DNSNames = append(template.DNSNames, h)
   128  		}
   129  	}
   130  
   131  	if isCA {
   132  		template.IsCA = true
   133  		template.KeyUsage |= x509.KeyUsageCertSign
   134  	}
   135  
   136  	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
   137  	if err != nil {
   138  		zap.S().Errorf("Failed to create certificate: %s", err)
   139  	}
   140  
   141  	certOut, err := os.CreateTemp(os.TempDir(), "cert")
   142  	if err != nil {
   143  		zap.S().Errorf("failed to open"+os.TempDir()+"/tls.crt for writing: %s", err)
   144  	}
   145  	err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
   146  	if err != nil {
   147  		zap.S().Errorf("Error encoding certificate: %s", err)
   148  	}
   149  
   150  	err = certOut.Close()
   151  	if err != nil {
   152  		zap.S().Errorf("Error closing cert file: %s", err)
   153  	}
   154  
   155  	fmt.Print("generated " + os.TempDir() + "/tls.crt\n")
   156  
   157  	keyOut, err := os.OpenFile(os.TempDir()+"/tls.key", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
   158  	if err != nil {
   159  		zap.S().Errorf("failed to open "+os.TempDir()+"/tls.key for writing:", err)
   160  		return err
   161  	}
   162  	err = pem.Encode(keyOut, pemBlockForKey(priv))
   163  	if err != nil {
   164  		zap.S().Errorf("Error encoding pem key: %s", err)
   165  	}
   166  	err = keyOut.Close()
   167  	if err != nil {
   168  		zap.S().Errorf("Error closing key: %s", err)
   169  	}
   170  	fmt.Print("generated " + os.TempDir() + "/tls.key\n")
   171  
   172  	return nil
   173  }