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 }