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 }