crypto.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package crypto
  14. import (
  15. "bytes"
  16. "crypto/rand"
  17. "crypto/rsa"
  18. "crypto/x509"
  19. "crypto/x509/pkix"
  20. "encoding/pem"
  21. "errors"
  22. "fmt"
  23. "io/ioutil"
  24. "math/big"
  25. "net"
  26. "os"
  27. "path/filepath"
  28. "time"
  29. )
  30. // FoundCertOrKey returns true if the certificate or key files already exists,
  31. // otherwise returns false.
  32. func FoundCertOrKey(certPath, keyPath string) bool {
  33. if canReadFile(certPath) || canReadFile(keyPath) {
  34. return true
  35. }
  36. return false
  37. }
  38. // If the file represented by path exists and
  39. // readable, returns true otherwise returns false.
  40. func canReadFile(path string) bool {
  41. f, err := os.Open(path)
  42. if err != nil {
  43. return false
  44. }
  45. defer f.Close()
  46. return true
  47. }
  48. // GenerateSelfSignedCert creates a self-signed certificate and key for the given host.
  49. // Host may be an IP or a DNS name
  50. // You may also specify additional subject alt names (either ip or dns names) for the certificate
  51. // The certificate will be created with file mode 0644. The key will be created with file mode 0600.
  52. // If the certificate or key files already exist, they will be overwritten.
  53. // Any parent directories of the certPath or keyPath will be created as needed with file mode 0755.
  54. func GenerateSelfSignedCert(host, certPath, keyPath string, alternateIPs []net.IP, alternateDNS []string) error {
  55. priv, err := rsa.GenerateKey(rand.Reader, 2048)
  56. if err != nil {
  57. return err
  58. }
  59. template := x509.Certificate{
  60. SerialNumber: big.NewInt(1),
  61. Subject: pkix.Name{
  62. CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()),
  63. },
  64. NotBefore: time.Now(),
  65. NotAfter: time.Now().Add(time.Hour * 24 * 365),
  66. KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
  67. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  68. BasicConstraintsValid: true,
  69. IsCA: true,
  70. }
  71. if ip := net.ParseIP(host); ip != nil {
  72. template.IPAddresses = append(template.IPAddresses, ip)
  73. } else {
  74. template.DNSNames = append(template.DNSNames, host)
  75. }
  76. template.IPAddresses = append(template.IPAddresses, alternateIPs...)
  77. template.DNSNames = append(template.DNSNames, alternateDNS...)
  78. derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
  79. if err != nil {
  80. return err
  81. }
  82. // Generate cert
  83. certBuffer := bytes.Buffer{}
  84. if err := pem.Encode(&certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
  85. return err
  86. }
  87. // Generate key
  88. keyBuffer := bytes.Buffer{}
  89. if err := pem.Encode(&keyBuffer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
  90. return err
  91. }
  92. // Write cert
  93. if err := WriteCertToPath(certPath, certBuffer.Bytes()); err != nil {
  94. return err
  95. }
  96. // Write key
  97. if err := WriteKeyToPath(keyPath, keyBuffer.Bytes()); err != nil {
  98. return err
  99. }
  100. return nil
  101. }
  102. // WriteCertToPath writes the pem-encoded certificate data to certPath.
  103. // The certificate file will be created with file mode 0644.
  104. // If the certificate file already exists, it will be overwritten.
  105. // The parent directory of the certPath will be created as needed with file mode 0755.
  106. func WriteCertToPath(certPath string, data []byte) error {
  107. if err := os.MkdirAll(filepath.Dir(certPath), os.FileMode(0755)); err != nil {
  108. return err
  109. }
  110. if err := ioutil.WriteFile(certPath, data, os.FileMode(0644)); err != nil {
  111. return err
  112. }
  113. return nil
  114. }
  115. // WriteKeyToPath writes the pem-encoded key data to keyPath.
  116. // The key file will be created with file mode 0600.
  117. // If the key file already exists, it will be overwritten.
  118. // The parent directory of the keyPath will be created as needed with file mode 0755.
  119. func WriteKeyToPath(keyPath string, data []byte) error {
  120. if err := os.MkdirAll(filepath.Dir(keyPath), os.FileMode(0755)); err != nil {
  121. return err
  122. }
  123. if err := ioutil.WriteFile(keyPath, data, os.FileMode(0600)); err != nil {
  124. return err
  125. }
  126. return nil
  127. }
  128. // CertPoolFromFile returns an x509.CertPool containing the certificates in the given PEM-encoded file.
  129. // 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
  130. func CertPoolFromFile(filename string) (*x509.CertPool, error) {
  131. certs, err := certificatesFromFile(filename)
  132. if err != nil {
  133. return nil, err
  134. }
  135. pool := x509.NewCertPool()
  136. for _, cert := range certs {
  137. pool.AddCert(cert)
  138. }
  139. return pool, nil
  140. }
  141. // certificatesFromFile returns the x509.Certificates contained in the given PEM-encoded file.
  142. // 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
  143. func certificatesFromFile(file string) ([]*x509.Certificate, error) {
  144. if len(file) == 0 {
  145. return nil, errors.New("error reading certificates from an empty filename")
  146. }
  147. pemBlock, err := ioutil.ReadFile(file)
  148. if err != nil {
  149. return nil, err
  150. }
  151. certs, err := CertsFromPEM(pemBlock)
  152. if err != nil {
  153. return nil, fmt.Errorf("error reading %s: %s", file, err)
  154. }
  155. return certs, nil
  156. }
  157. // CertsFromPEM returns the x509.Certificates contained in the given PEM-encoded byte array
  158. // Returns an error if a certificate could not be parsed, or if the data does not contain any certificates
  159. func CertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) {
  160. ok := false
  161. certs := []*x509.Certificate{}
  162. for len(pemCerts) > 0 {
  163. var block *pem.Block
  164. block, pemCerts = pem.Decode(pemCerts)
  165. if block == nil {
  166. break
  167. }
  168. // Only use PEM "CERTIFICATE" blocks without extra headers
  169. if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
  170. continue
  171. }
  172. cert, err := x509.ParseCertificate(block.Bytes)
  173. if err != nil {
  174. return certs, err
  175. }
  176. certs = append(certs, cert)
  177. ok = true
  178. }
  179. if !ok {
  180. return certs, errors.New("could not read any certificates")
  181. }
  182. return certs, nil
  183. }