github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/k8s.io/kubernetes/pkg/util/crypto.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors All rights reserved. 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 util 18 19 import ( 20 "bytes" 21 "crypto/rand" 22 "crypto/rsa" 23 "crypto/x509" 24 "crypto/x509/pkix" 25 "encoding/pem" 26 "errors" 27 "fmt" 28 "io/ioutil" 29 "math/big" 30 "net" 31 "os" 32 "path/filepath" 33 "time" 34 ) 35 36 // GenerateSelfSignedCert creates a self-signed certificate and key for the given host. 37 // Host may be an IP or a DNS name 38 // You may also specify additional subject alt names (either ip or dns names) for the certificate 39 // The certificate will be created with file mode 0644. The key will be created with file mode 0600. 40 // If the certificate or key files already exist, they will be overwritten. 41 // Any parent directories of the certPath or keyPath will be created as needed with file mode 0755. 42 func GenerateSelfSignedCert(host, certPath, keyPath string, alternateIPs []net.IP, alternateDNS []string) error { 43 priv, err := rsa.GenerateKey(rand.Reader, 2048) 44 if err != nil { 45 return err 46 } 47 48 template := x509.Certificate{ 49 SerialNumber: big.NewInt(1), 50 Subject: pkix.Name{ 51 CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()), 52 }, 53 NotBefore: time.Now(), 54 NotAfter: time.Now().Add(time.Hour * 24 * 365), 55 56 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, 57 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 58 BasicConstraintsValid: true, 59 IsCA: true, 60 } 61 62 if ip := net.ParseIP(host); ip != nil { 63 template.IPAddresses = append(template.IPAddresses, ip) 64 } else { 65 template.DNSNames = append(template.DNSNames, host) 66 } 67 68 template.IPAddresses = append(template.IPAddresses, alternateIPs...) 69 template.DNSNames = append(template.DNSNames, alternateDNS...) 70 71 derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) 72 if err != nil { 73 return err 74 } 75 76 // Generate cert 77 certBuffer := bytes.Buffer{} 78 if err := pem.Encode(&certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { 79 return err 80 } 81 82 // Generate key 83 keyBuffer := bytes.Buffer{} 84 if err := pem.Encode(&keyBuffer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil { 85 return err 86 } 87 88 // Write cert 89 if err := os.MkdirAll(filepath.Dir(certPath), os.FileMode(0755)); err != nil { 90 return err 91 } 92 if err := ioutil.WriteFile(certPath, certBuffer.Bytes(), os.FileMode(0644)); err != nil { 93 return err 94 } 95 96 // Write key 97 if err := os.MkdirAll(filepath.Dir(keyPath), os.FileMode(0755)); err != nil { 98 return err 99 } 100 if err := ioutil.WriteFile(keyPath, keyBuffer.Bytes(), os.FileMode(0600)); err != nil { 101 return err 102 } 103 104 return nil 105 } 106 107 // CertPoolFromFile returns an x509.CertPool containing the certificates in the given PEM-encoded file. 108 // Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates 109 func CertPoolFromFile(filename string) (*x509.CertPool, error) { 110 certs, err := certificatesFromFile(filename) 111 if err != nil { 112 return nil, err 113 } 114 pool := x509.NewCertPool() 115 for _, cert := range certs { 116 pool.AddCert(cert) 117 } 118 return pool, nil 119 } 120 121 // certificatesFromFile returns the x509.Certificates contained in the given PEM-encoded file. 122 // Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates 123 func certificatesFromFile(file string) ([]*x509.Certificate, error) { 124 if len(file) == 0 { 125 return nil, errors.New("error reading certificates from an empty filename") 126 } 127 pemBlock, err := ioutil.ReadFile(file) 128 if err != nil { 129 return nil, err 130 } 131 certs, err := CertsFromPEM(pemBlock) 132 if err != nil { 133 return nil, fmt.Errorf("error reading %s: %s", file, err) 134 } 135 return certs, nil 136 } 137 138 // CertsFromPEM returns the x509.Certificates contained in the given PEM-encoded byte array 139 // Returns an error if a certificate could not be parsed, or if the data does not contain any certificates 140 func CertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) { 141 ok := false 142 certs := []*x509.Certificate{} 143 for len(pemCerts) > 0 { 144 var block *pem.Block 145 block, pemCerts = pem.Decode(pemCerts) 146 if block == nil { 147 break 148 } 149 // Only use PEM "CERTIFICATE" blocks without extra headers 150 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { 151 continue 152 } 153 154 cert, err := x509.ParseCertificate(block.Bytes) 155 if err != nil { 156 return certs, err 157 } 158 159 certs = append(certs, cert) 160 ok = true 161 } 162 163 if !ok { 164 return certs, errors.New("could not read any certificates") 165 } 166 return certs, nil 167 }