package x509 import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "math" "math/big" "net" "time" "k8s.io/client-go/util/keyutil" pem "edge-infra.dev/pkg/lib/crypto/certs/pem" ) type CertInfo struct { Name string CommonName string Organization []string DNSNames []string IPs []net.IP Usages []x509.ExtKeyUsage } type EncodedKeyPair struct { Key []byte Cert []byte } // Utility for abstracting private key creation, public cert generation, cert and key encoding and return func GenerateCertAndKey(certInfo CertInfo, caCert *x509.Certificate, caKeySigner crypto.Signer) (encodedKeyPair EncodedKeyPair, err error) { key, err := GenPrivateKey() if err != nil { return } x509CertBytes, err := GenPublicCert(certInfo, key, caCert, caKeySigner) if err != nil { return } encodedKey, _ := keyutil.MarshalPrivateKeyToPEM(key) encodedCert := pem.Encodex509CertAsPem(x509CertBytes) encodedKeyPair = EncodedKeyPair{ Key: encodedKey, Cert: encodedCert, } return } // Creates RSA private key func GenPrivateKey() (crypto.Signer, error) { return rsa.GenerateKey(rand.Reader, 2048) } // Abstracts serial number generation, x509 cert struct declaration and creation with one year expiry // Returns bytes of the x509 cert func GenPublicCert(ci CertInfo, key crypto.Signer, caCert *x509.Certificate, caKey crypto.Signer) ([]byte, error) { serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) if err != nil { return nil, err } notAfter := time.Now().Add(time.Hour * 24 * 365).UTC() certTmpl := x509.Certificate{ Subject: pkix.Name{ CommonName: ci.CommonName, Organization: ci.Organization, }, DNSNames: ci.DNSNames, IPAddresses: ci.IPs, SerialNumber: serial, NotBefore: caCert.NotBefore, NotAfter: notAfter, KeyUsage: 3, ExtKeyUsage: ci.Usages, BasicConstraintsValid: true, IsCA: false, } certDERBytes, err := x509.CreateCertificate(rand.Reader, &certTmpl, caCert, key.Public(), caKey) if err != nil { return nil, err } return certDERBytes, nil }