github.com/openshift/installer@v1.4.17/pkg/asset/tls/tls.go (about) 1 package tls 2 3 import ( 4 "crypto" 5 "crypto/ecdsa" 6 "crypto/elliptic" 7 "crypto/rand" 8 "crypto/rsa" 9 "crypto/sha1" 10 "crypto/x509" 11 "crypto/x509/pkix" 12 "encoding/asn1" 13 "math" 14 "math/big" 15 "net" 16 "time" 17 18 "github.com/pkg/errors" 19 "github.com/sirupsen/logrus" 20 ) 21 22 const ( 23 keySize = 2048 24 25 // ValidityOneDay sets the validity of a cert to 24 hours. 26 ValidityOneDay = time.Hour * 24 27 28 // ValidityOneYear sets the validity of a cert to 1 year. 29 ValidityOneYear = ValidityOneDay * 365 30 31 // ValidityTenYears sets the validity of a cert to 10 years. 32 ValidityTenYears = ValidityOneYear * 10 33 ) 34 35 // CertCfg contains all needed fields to configure a new certificate 36 type CertCfg struct { 37 DNSNames []string 38 ExtKeyUsages []x509.ExtKeyUsage 39 IPAddresses []net.IP 40 KeyUsages x509.KeyUsage 41 Subject pkix.Name 42 Validity time.Duration 43 IsCA bool 44 } 45 46 // rsaPublicKey reflects the ASN.1 structure of a PKCS#1 public key. 47 type rsaPublicKey struct { 48 N *big.Int 49 E int 50 } 51 52 // PrivateKey generates an RSA Private key and returns the value 53 func PrivateKey() (*rsa.PrivateKey, error) { 54 rsaKey, err := rsa.GenerateKey(rand.Reader, keySize) 55 if err != nil { 56 return nil, errors.Wrap(err, "error generating RSA private key") 57 } 58 59 return rsaKey, nil 60 } 61 62 // SelfSignedCertificate creates a self signed certificate 63 func SelfSignedCertificate(cfg *CertCfg, key *rsa.PrivateKey) (*x509.Certificate, error) { 64 serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) 65 if err != nil { 66 return nil, err 67 } 68 cert := x509.Certificate{ 69 BasicConstraintsValid: true, 70 IsCA: cfg.IsCA, 71 KeyUsage: cfg.KeyUsages, 72 NotAfter: time.Now().Add(cfg.Validity), 73 NotBefore: time.Now(), 74 SerialNumber: serial, 75 Subject: cfg.Subject, 76 } 77 // verifies that the CN and/or OU for the cert is set 78 if len(cfg.Subject.CommonName) == 0 || len(cfg.Subject.OrganizationalUnit) == 0 { 79 return nil, errors.Errorf("certification's subject is not set, or invalid") 80 } 81 pub := key.Public() 82 cert.SubjectKeyId, err = generateSubjectKeyID(pub) 83 if err != nil { 84 return nil, errors.Wrap(err, "failed to set subject key identifier") 85 } 86 certBytes, err := x509.CreateCertificate(rand.Reader, &cert, &cert, key.Public(), key) 87 if err != nil { 88 return nil, errors.Wrap(err, "failed to create certificate") 89 } 90 return x509.ParseCertificate(certBytes) 91 } 92 93 // SignedCertificate creates a new X.509 certificate based on a template. 94 func SignedCertificate( 95 cfg *CertCfg, 96 csr *x509.CertificateRequest, 97 key *rsa.PrivateKey, 98 caCert *x509.Certificate, 99 caKey *rsa.PrivateKey, 100 ) (*x509.Certificate, error) { 101 serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) 102 if err != nil { 103 return nil, err 104 } 105 106 certTmpl := x509.Certificate{ 107 DNSNames: csr.DNSNames, 108 ExtKeyUsage: cfg.ExtKeyUsages, 109 IPAddresses: csr.IPAddresses, 110 KeyUsage: cfg.KeyUsages, 111 NotAfter: time.Now().Add(cfg.Validity), 112 NotBefore: caCert.NotBefore, 113 SerialNumber: serial, 114 Subject: csr.Subject, 115 IsCA: cfg.IsCA, 116 Version: 3, 117 BasicConstraintsValid: true, 118 } 119 pub := key.Public() 120 certTmpl.SubjectKeyId, err = generateSubjectKeyID(pub) 121 if err != nil { 122 return nil, errors.Wrap(err, "failed to set subject key identifier") 123 } 124 certBytes, err := x509.CreateCertificate(rand.Reader, &certTmpl, caCert, key.Public(), caKey) 125 if err != nil { 126 return nil, errors.Wrap(err, "failed to create x509 certificate") 127 } 128 return x509.ParseCertificate(certBytes) 129 } 130 131 // generateSubjectKeyID generates a SHA-1 hash of the subject public key. 132 func generateSubjectKeyID(pub crypto.PublicKey) ([]byte, error) { 133 var publicKeyBytes []byte 134 var err error 135 136 switch pub := pub.(type) { 137 case *rsa.PublicKey: 138 publicKeyBytes, err = asn1.Marshal(rsaPublicKey{N: pub.N, E: pub.E}) 139 if err != nil { 140 return nil, errors.Wrap(err, "failed to Marshal ans1 public key") 141 } 142 case *ecdsa.PublicKey: 143 publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) 144 default: 145 return nil, errors.New("only RSA and ECDSA public keys supported") 146 } 147 148 hash := sha1.Sum(publicKeyBytes) 149 return hash[:], nil 150 } 151 152 // GenerateSignedCertificate generate a key and cert defined by CertCfg and signed by CA. 153 func GenerateSignedCertificate(caKey *rsa.PrivateKey, caCert *x509.Certificate, 154 cfg *CertCfg) (*rsa.PrivateKey, *x509.Certificate, error) { 155 156 // create a private key 157 key, err := PrivateKey() 158 if err != nil { 159 return nil, nil, errors.Wrap(err, "failed to generate private key") 160 } 161 162 // create a CSR 163 csrTmpl := x509.CertificateRequest{Subject: cfg.Subject, DNSNames: cfg.DNSNames, IPAddresses: cfg.IPAddresses} 164 csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &csrTmpl, key) 165 if err != nil { 166 return nil, nil, errors.Wrap(err, "failed to create certificate request") 167 } 168 169 csr, err := x509.ParseCertificateRequest(csrBytes) 170 if err != nil { 171 logrus.Debugf("Failed to parse x509 certificate request: %s", err) 172 return nil, nil, errors.Wrap(err, "error parsing x509 certificate request") 173 } 174 175 // create a cert 176 cert, err := SignedCertificate(cfg, csr, key, caCert, caKey) 177 if err != nil { 178 logrus.Debugf("Failed to create a signed certificate: %s", err) 179 return nil, nil, errors.Wrap(err, "failed to create a signed certificate") 180 } 181 return key, cert, nil 182 } 183 184 // GenerateSelfSignedCertificate generates a key/cert pair defined by CertCfg. 185 func GenerateSelfSignedCertificate(cfg *CertCfg) (*rsa.PrivateKey, *x509.Certificate, error) { 186 key, err := PrivateKey() 187 if err != nil { 188 logrus.Debugf("Failed to generate a private key: %s", err) 189 return nil, nil, errors.Wrap(err, "failed to generate private key") 190 } 191 192 crt, err := SelfSignedCertificate(cfg, key) 193 if err != nil { 194 logrus.Debugf("Failed to create self-signed certificate: %s", err) 195 return nil, nil, errors.Wrap(err, "failed to create self-signed certificate") 196 } 197 return key, crt, nil 198 }