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  }