123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- /*
- Copyright 2014 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package crypto
- import (
- "bytes"
- "crypto/rand"
- "crypto/rsa"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/pem"
- "errors"
- "fmt"
- "io/ioutil"
- "math/big"
- "net"
- "os"
- "path/filepath"
- "time"
- )
- // FoundCertOrKey returns true if the certificate or key files already exists,
- // otherwise returns false.
- func FoundCertOrKey(certPath, keyPath string) bool {
- if canReadFile(certPath) || canReadFile(keyPath) {
- return true
- }
- return false
- }
- // If the file represented by path exists and
- // readable, returns true otherwise returns false.
- func canReadFile(path string) bool {
- f, err := os.Open(path)
- if err != nil {
- return false
- }
- defer f.Close()
- return true
- }
- // GenerateSelfSignedCert creates a self-signed certificate and key for the given host.
- // Host may be an IP or a DNS name
- // You may also specify additional subject alt names (either ip or dns names) for the certificate
- // The certificate will be created with file mode 0644. The key will be created with file mode 0600.
- // If the certificate or key files already exist, they will be overwritten.
- // Any parent directories of the certPath or keyPath will be created as needed with file mode 0755.
- func GenerateSelfSignedCert(host, certPath, keyPath string, alternateIPs []net.IP, alternateDNS []string) error {
- priv, err := rsa.GenerateKey(rand.Reader, 2048)
- if err != nil {
- return err
- }
- template := x509.Certificate{
- SerialNumber: big.NewInt(1),
- Subject: pkix.Name{
- CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()),
- },
- NotBefore: time.Now(),
- NotAfter: time.Now().Add(time.Hour * 24 * 365),
- KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
- ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
- BasicConstraintsValid: true,
- IsCA: true,
- }
- if ip := net.ParseIP(host); ip != nil {
- template.IPAddresses = append(template.IPAddresses, ip)
- } else {
- template.DNSNames = append(template.DNSNames, host)
- }
- template.IPAddresses = append(template.IPAddresses, alternateIPs...)
- template.DNSNames = append(template.DNSNames, alternateDNS...)
- derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
- if err != nil {
- return err
- }
- // Generate cert
- certBuffer := bytes.Buffer{}
- if err := pem.Encode(&certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
- return err
- }
- // Generate key
- keyBuffer := bytes.Buffer{}
- if err := pem.Encode(&keyBuffer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
- return err
- }
- // Write cert
- if err := WriteCertToPath(certPath, certBuffer.Bytes()); err != nil {
- return err
- }
- // Write key
- if err := WriteKeyToPath(keyPath, keyBuffer.Bytes()); err != nil {
- return err
- }
- return nil
- }
- // WriteCertToPath writes the pem-encoded certificate data to certPath.
- // The certificate file will be created with file mode 0644.
- // If the certificate file already exists, it will be overwritten.
- // The parent directory of the certPath will be created as needed with file mode 0755.
- func WriteCertToPath(certPath string, data []byte) error {
- if err := os.MkdirAll(filepath.Dir(certPath), os.FileMode(0755)); err != nil {
- return err
- }
- if err := ioutil.WriteFile(certPath, data, os.FileMode(0644)); err != nil {
- return err
- }
- return nil
- }
- // WriteKeyToPath writes the pem-encoded key data to keyPath.
- // The key file will be created with file mode 0600.
- // If the key file already exists, it will be overwritten.
- // The parent directory of the keyPath will be created as needed with file mode 0755.
- func WriteKeyToPath(keyPath string, data []byte) error {
- if err := os.MkdirAll(filepath.Dir(keyPath), os.FileMode(0755)); err != nil {
- return err
- }
- if err := ioutil.WriteFile(keyPath, data, os.FileMode(0600)); err != nil {
- return err
- }
- return nil
- }
- // CertPoolFromFile returns an x509.CertPool containing the certificates in the given PEM-encoded file.
- // 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
- func CertPoolFromFile(filename string) (*x509.CertPool, error) {
- certs, err := certificatesFromFile(filename)
- if err != nil {
- return nil, err
- }
- pool := x509.NewCertPool()
- for _, cert := range certs {
- pool.AddCert(cert)
- }
- return pool, nil
- }
- // certificatesFromFile returns the x509.Certificates contained in the given PEM-encoded file.
- // 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
- func certificatesFromFile(file string) ([]*x509.Certificate, error) {
- if len(file) == 0 {
- return nil, errors.New("error reading certificates from an empty filename")
- }
- pemBlock, err := ioutil.ReadFile(file)
- if err != nil {
- return nil, err
- }
- certs, err := CertsFromPEM(pemBlock)
- if err != nil {
- return nil, fmt.Errorf("error reading %s: %s", file, err)
- }
- return certs, nil
- }
- // CertsFromPEM returns the x509.Certificates contained in the given PEM-encoded byte array
- // Returns an error if a certificate could not be parsed, or if the data does not contain any certificates
- func CertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) {
- ok := false
- certs := []*x509.Certificate{}
- for len(pemCerts) > 0 {
- var block *pem.Block
- block, pemCerts = pem.Decode(pemCerts)
- if block == nil {
- break
- }
- // Only use PEM "CERTIFICATE" blocks without extra headers
- if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
- continue
- }
- cert, err := x509.ParseCertificate(block.Bytes)
- if err != nil {
- return certs, err
- }
- certs = append(certs, cert)
- ok = true
- }
- if !ok {
- return certs, errors.New("could not read any certificates")
- }
- return certs, nil
- }
|