Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / k8s.io / client-go / util / cert / cert.go
1 /*
2 Copyright 2014 The Kubernetes Authors.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8     http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 package cert
18
19 import (
20         "bytes"
21         "crypto"
22         "crypto/ecdsa"
23         "crypto/elliptic"
24         "crypto/rand"
25         cryptorand "crypto/rand"
26         "crypto/rsa"
27         "crypto/x509"
28         "crypto/x509/pkix"
29         "encoding/pem"
30         "errors"
31         "fmt"
32         "io/ioutil"
33         "math"
34         "math/big"
35         "net"
36         "path"
37         "strings"
38         "time"
39 )
40
41 const (
42         rsaKeySize   = 2048
43         duration365d = time.Hour * 24 * 365
44 )
45
46 // Config contains the basic fields required for creating a certificate
47 type Config struct {
48         CommonName   string
49         Organization []string
50         AltNames     AltNames
51         Usages       []x509.ExtKeyUsage
52 }
53
54 // AltNames contains the domain names and IP addresses that will be added
55 // to the API Server's x509 certificate SubAltNames field. The values will
56 // be passed directly to the x509.Certificate object.
57 type AltNames struct {
58         DNSNames []string
59         IPs      []net.IP
60 }
61
62 // NewPrivateKey creates an RSA private key
63 func NewPrivateKey() (*rsa.PrivateKey, error) {
64         return rsa.GenerateKey(cryptorand.Reader, rsaKeySize)
65 }
66
67 // NewSelfSignedCACert creates a CA certificate
68 func NewSelfSignedCACert(cfg Config, key crypto.Signer) (*x509.Certificate, error) {
69         now := time.Now()
70         tmpl := x509.Certificate{
71                 SerialNumber: new(big.Int).SetInt64(0),
72                 Subject: pkix.Name{
73                         CommonName:   cfg.CommonName,
74                         Organization: cfg.Organization,
75                 },
76                 NotBefore:             now.UTC(),
77                 NotAfter:              now.Add(duration365d * 10).UTC(),
78                 KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
79                 BasicConstraintsValid: true,
80                 IsCA:                  true,
81         }
82
83         certDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &tmpl, &tmpl, key.Public(), key)
84         if err != nil {
85                 return nil, err
86         }
87         return x509.ParseCertificate(certDERBytes)
88 }
89
90 // NewSignedCert creates a signed certificate using the given CA certificate and key
91 func NewSignedCert(cfg Config, key crypto.Signer, caCert *x509.Certificate, caKey crypto.Signer) (*x509.Certificate, error) {
92         serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
93         if err != nil {
94                 return nil, err
95         }
96         if len(cfg.CommonName) == 0 {
97                 return nil, errors.New("must specify a CommonName")
98         }
99         if len(cfg.Usages) == 0 {
100                 return nil, errors.New("must specify at least one ExtKeyUsage")
101         }
102
103         certTmpl := x509.Certificate{
104                 Subject: pkix.Name{
105                         CommonName:   cfg.CommonName,
106                         Organization: cfg.Organization,
107                 },
108                 DNSNames:     cfg.AltNames.DNSNames,
109                 IPAddresses:  cfg.AltNames.IPs,
110                 SerialNumber: serial,
111                 NotBefore:    caCert.NotBefore,
112                 NotAfter:     time.Now().Add(duration365d).UTC(),
113                 KeyUsage:     x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
114                 ExtKeyUsage:  cfg.Usages,
115         }
116         certDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &certTmpl, caCert, key.Public(), caKey)
117         if err != nil {
118                 return nil, err
119         }
120         return x509.ParseCertificate(certDERBytes)
121 }
122
123 // MakeEllipticPrivateKeyPEM creates an ECDSA private key
124 func MakeEllipticPrivateKeyPEM() ([]byte, error) {
125         privateKey, err := ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
126         if err != nil {
127                 return nil, err
128         }
129
130         derBytes, err := x509.MarshalECPrivateKey(privateKey)
131         if err != nil {
132                 return nil, err
133         }
134
135         privateKeyPemBlock := &pem.Block{
136                 Type:  ECPrivateKeyBlockType,
137                 Bytes: derBytes,
138         }
139         return pem.EncodeToMemory(privateKeyPemBlock), nil
140 }
141
142 // GenerateSelfSignedCertKey creates a self-signed certificate and key for the given host.
143 // Host may be an IP or a DNS name
144 // You may also specify additional subject alt names (either ip or dns names) for the certificate.
145 func GenerateSelfSignedCertKey(host string, alternateIPs []net.IP, alternateDNS []string) ([]byte, []byte, error) {
146         return GenerateSelfSignedCertKeyWithFixtures(host, alternateIPs, alternateDNS, "")
147 }
148
149 // GenerateSelfSignedCertKeyWithFixtures creates a self-signed certificate and key for the given host.
150 // Host may be an IP or a DNS name. You may also specify additional subject alt names (either ip or dns names)
151 // for the certificate.
152 //
153 // If fixtureDirectory is non-empty, it is a directory path which can contain pre-generated certs. The format is:
154 // <host>_<ip>-<ip>_<alternateDNS>-<alternateDNS>.crt
155 // <host>_<ip>-<ip>_<alternateDNS>-<alternateDNS>.key
156 // Certs/keys not existing in that directory are created.
157 func GenerateSelfSignedCertKeyWithFixtures(host string, alternateIPs []net.IP, alternateDNS []string, fixtureDirectory string) ([]byte, []byte, error) {
158         validFrom := time.Now().Add(-time.Hour) // valid an hour earlier to avoid flakes due to clock skew
159         maxAge := time.Hour * 24 * 365          // one year self-signed certs
160
161         baseName := fmt.Sprintf("%s_%s_%s", host, strings.Join(ipsToStrings(alternateIPs), "-"), strings.Join(alternateDNS, "-"))
162         certFixturePath := path.Join(fixtureDirectory, baseName+".crt")
163         keyFixturePath := path.Join(fixtureDirectory, baseName+".key")
164         if len(fixtureDirectory) > 0 {
165                 cert, err := ioutil.ReadFile(certFixturePath)
166                 if err == nil {
167                         key, err := ioutil.ReadFile(keyFixturePath)
168                         if err == nil {
169                                 return cert, key, nil
170                         }
171                         return nil, nil, fmt.Errorf("cert %s can be read, but key %s cannot: %v", certFixturePath, keyFixturePath, err)
172                 }
173                 maxAge = 100 * time.Hour * 24 * 365 // 100 years fixtures
174         }
175
176         caKey, err := rsa.GenerateKey(cryptorand.Reader, 2048)
177         if err != nil {
178                 return nil, nil, err
179         }
180
181         caTemplate := x509.Certificate{
182                 SerialNumber: big.NewInt(1),
183                 Subject: pkix.Name{
184                         CommonName: fmt.Sprintf("%s-ca@%d", host, time.Now().Unix()),
185                 },
186                 NotBefore: validFrom,
187                 NotAfter:  validFrom.Add(maxAge),
188
189                 KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
190                 BasicConstraintsValid: true,
191                 IsCA:                  true,
192         }
193
194         caDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &caTemplate, &caTemplate, &caKey.PublicKey, caKey)
195         if err != nil {
196                 return nil, nil, err
197         }
198
199         caCertificate, err := x509.ParseCertificate(caDERBytes)
200         if err != nil {
201                 return nil, nil, err
202         }
203
204         priv, err := rsa.GenerateKey(cryptorand.Reader, 2048)
205         if err != nil {
206                 return nil, nil, err
207         }
208
209         template := x509.Certificate{
210                 SerialNumber: big.NewInt(2),
211                 Subject: pkix.Name{
212                         CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()),
213                 },
214                 NotBefore: validFrom,
215                 NotAfter:  validFrom.Add(maxAge),
216
217                 KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
218                 ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
219                 BasicConstraintsValid: true,
220         }
221
222         if ip := net.ParseIP(host); ip != nil {
223                 template.IPAddresses = append(template.IPAddresses, ip)
224         } else {
225                 template.DNSNames = append(template.DNSNames, host)
226         }
227
228         template.IPAddresses = append(template.IPAddresses, alternateIPs...)
229         template.DNSNames = append(template.DNSNames, alternateDNS...)
230
231         derBytes, err := x509.CreateCertificate(cryptorand.Reader, &template, caCertificate, &priv.PublicKey, caKey)
232         if err != nil {
233                 return nil, nil, err
234         }
235
236         // Generate cert, followed by ca
237         certBuffer := bytes.Buffer{}
238         if err := pem.Encode(&certBuffer, &pem.Block{Type: CertificateBlockType, Bytes: derBytes}); err != nil {
239                 return nil, nil, err
240         }
241         if err := pem.Encode(&certBuffer, &pem.Block{Type: CertificateBlockType, Bytes: caDERBytes}); err != nil {
242                 return nil, nil, err
243         }
244
245         // Generate key
246         keyBuffer := bytes.Buffer{}
247         if err := pem.Encode(&keyBuffer, &pem.Block{Type: RSAPrivateKeyBlockType, Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
248                 return nil, nil, err
249         }
250
251         if len(fixtureDirectory) > 0 {
252                 if err := ioutil.WriteFile(certFixturePath, certBuffer.Bytes(), 0644); err != nil {
253                         return nil, nil, fmt.Errorf("failed to write cert fixture to %s: %v", certFixturePath, err)
254                 }
255                 if err := ioutil.WriteFile(keyFixturePath, keyBuffer.Bytes(), 0644); err != nil {
256                         return nil, nil, fmt.Errorf("failed to write key fixture to %s: %v", certFixturePath, err)
257                 }
258         }
259
260         return certBuffer.Bytes(), keyBuffer.Bytes(), nil
261 }
262
263 func ipsToStrings(ips []net.IP) []string {
264         ss := make([]string, 0, len(ips))
265         for _, ip := range ips {
266                 ss = append(ss, ip.String())
267         }
268         return ss
269 }