github.com/docker/compose-on-kubernetes@v0.5.0/internal/keys/keys.go (about)

     1  package keys
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/ecdsa"
     6  	"crypto/elliptic"
     7  	cryptorand "crypto/rand"
     8  	"crypto/rsa"
     9  	"crypto/x509"
    10  	"crypto/x509/pkix"
    11  	"encoding/pem"
    12  	"errors"
    13  	"math"
    14  	"math/big"
    15  	"time"
    16  
    17  	certutil "k8s.io/client-go/util/cert"
    18  	"k8s.io/client-go/util/keyutil"
    19  )
    20  
    21  const duration365d = time.Hour * 24 * 365
    22  
    23  // SignerWithPEM is a signer implementation that has its PEM encoded representation attached
    24  type SignerWithPEM interface {
    25  	crypto.Signer
    26  	PEM() []byte
    27  }
    28  
    29  type signerWithPEM struct {
    30  	crypto.Signer
    31  	pemData []byte
    32  }
    33  
    34  func (s signerWithPEM) PEM() []byte {
    35  	return s.pemData
    36  }
    37  
    38  // CA is a certificate authority usable to generated signed certificates
    39  type CA interface {
    40  	PrivateKey() SignerWithPEM
    41  	Cert() *x509.Certificate
    42  	NewSignedCert(cfg certutil.Config, publicKey crypto.PublicKey) (*x509.Certificate, error)
    43  }
    44  
    45  type authority struct {
    46  	pvk  SignerWithPEM
    47  	cert *x509.Certificate
    48  }
    49  
    50  func (ca *authority) PrivateKey() SignerWithPEM {
    51  	return ca.pvk
    52  }
    53  
    54  func (ca *authority) Cert() *x509.Certificate {
    55  	return ca.cert
    56  }
    57  
    58  func (ca *authority) NewSignedCert(cfg certutil.Config, publicKey crypto.PublicKey) (*x509.Certificate, error) {
    59  	serial, err := cryptorand.Int(cryptorand.Reader, new(big.Int).SetInt64(math.MaxInt64))
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	if len(cfg.CommonName) == 0 {
    64  		return nil, errors.New("must specify a CommonName")
    65  	}
    66  	if len(cfg.Usages) == 0 {
    67  		return nil, errors.New("must specify at least one ExtKeyUsage")
    68  	}
    69  	certTmpl := x509.Certificate{
    70  		Subject: pkix.Name{
    71  			CommonName:   cfg.CommonName,
    72  			Organization: cfg.Organization,
    73  		},
    74  		DNSNames:     cfg.AltNames.DNSNames,
    75  		IPAddresses:  cfg.AltNames.IPs,
    76  		SerialNumber: serial,
    77  		NotBefore:    ca.cert.NotBefore,
    78  		NotAfter:     time.Now().Add(time.Hour * 24 * 365).UTC(),
    79  		KeyUsage:     x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
    80  		ExtKeyUsage:  cfg.Usages,
    81  	}
    82  	certDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &certTmpl, ca.cert, publicKey, ca.pvk)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	cert, err := x509.ParseCertificate(certDERBytes)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	return cert, nil
    91  }
    92  
    93  // NewSelfSignedCA creates a CA and return it with its private key
    94  func NewSelfSignedCA(commonName string, organization []string) (CA, error) {
    95  	pvk, err := ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	derBytes, err := x509.MarshalECPrivateKey(pvk)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	keyPemBlock := &pem.Block{
   104  		Type:  keyutil.ECPrivateKeyBlockType,
   105  		Bytes: derBytes,
   106  	}
   107  	keyData := pem.EncodeToMemory(keyPemBlock)
   108  	key := signerWithPEM{Signer: pvk, pemData: keyData}
   109  
   110  	now := time.Now()
   111  	tmpl := x509.Certificate{
   112  		SerialNumber: new(big.Int).SetInt64(0),
   113  		Subject: pkix.Name{
   114  			CommonName:   commonName,
   115  			Organization: organization,
   116  		},
   117  		NotBefore:             now.UTC(),
   118  		NotAfter:              now.Add(duration365d * 10).UTC(),
   119  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
   120  		BasicConstraintsValid: true,
   121  		IsCA:                  true,
   122  	}
   123  
   124  	certDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &tmpl, &tmpl, key.Public(), key)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	cert, err := x509.ParseCertificate(certDERBytes)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	return &authority{
   133  		cert: cert,
   134  		pvk:  key,
   135  	}, nil
   136  }
   137  
   138  // NewRSASigner generates a private key suitable for a TLS cert (client or server)
   139  func NewRSASigner() (SignerWithPEM, error) {
   140  	key, err := rsa.GenerateKey(cryptorand.Reader, 2048)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  	pemData, err := keyutil.MarshalPrivateKeyToPEM(key)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	return signerWithPEM{Signer: key, pemData: pemData}, nil
   149  }
   150  
   151  // EncodeCertPEM embed a certificate in a PEM block
   152  func EncodeCertPEM(cert *x509.Certificate) []byte {
   153  	block := pem.Block{
   154  		Type:  "CERTIFICATE",
   155  		Bytes: cert.Raw,
   156  	}
   157  	return pem.EncodeToMemory(&block)
   158  }