certificates.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package libtrust
  2. import (
  3. "crypto/rand"
  4. "crypto/x509"
  5. "crypto/x509/pkix"
  6. "encoding/pem"
  7. "fmt"
  8. "io/ioutil"
  9. "math/big"
  10. "net"
  11. "time"
  12. )
  13. type certTemplateInfo struct {
  14. commonName string
  15. domains []string
  16. ipAddresses []net.IP
  17. isCA bool
  18. clientAuth bool
  19. serverAuth bool
  20. }
  21. func generateCertTemplate(info *certTemplateInfo) *x509.Certificate {
  22. // Generate a certificate template which is valid from the past week to
  23. // 10 years from now. The usage of the certificate depends on the
  24. // specified fields in the given certTempInfo object.
  25. var (
  26. keyUsage x509.KeyUsage
  27. extKeyUsage []x509.ExtKeyUsage
  28. )
  29. if info.isCA {
  30. keyUsage = x509.KeyUsageCertSign
  31. }
  32. if info.clientAuth {
  33. extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageClientAuth)
  34. }
  35. if info.serverAuth {
  36. extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageServerAuth)
  37. }
  38. return &x509.Certificate{
  39. SerialNumber: big.NewInt(0),
  40. Subject: pkix.Name{
  41. CommonName: info.commonName,
  42. },
  43. NotBefore: time.Now().Add(-time.Hour * 24 * 7),
  44. NotAfter: time.Now().Add(time.Hour * 24 * 365 * 10),
  45. DNSNames: info.domains,
  46. IPAddresses: info.ipAddresses,
  47. IsCA: info.isCA,
  48. KeyUsage: keyUsage,
  49. ExtKeyUsage: extKeyUsage,
  50. BasicConstraintsValid: info.isCA,
  51. }
  52. }
  53. func generateCert(pub PublicKey, priv PrivateKey, subInfo, issInfo *certTemplateInfo) (cert *x509.Certificate, err error) {
  54. pubCertTemplate := generateCertTemplate(subInfo)
  55. privCertTemplate := generateCertTemplate(issInfo)
  56. certDER, err := x509.CreateCertificate(
  57. rand.Reader, pubCertTemplate, privCertTemplate,
  58. pub.CryptoPublicKey(), priv.CryptoPrivateKey(),
  59. )
  60. if err != nil {
  61. return nil, fmt.Errorf("failed to create certificate: %s", err)
  62. }
  63. cert, err = x509.ParseCertificate(certDER)
  64. if err != nil {
  65. return nil, fmt.Errorf("failed to parse certificate: %s", err)
  66. }
  67. return
  68. }
  69. // GenerateSelfSignedServerCert creates a self-signed certificate for the
  70. // given key which is to be used for TLS servers with the given domains and
  71. // IP addresses.
  72. func GenerateSelfSignedServerCert(key PrivateKey, domains []string, ipAddresses []net.IP) (*x509.Certificate, error) {
  73. info := &certTemplateInfo{
  74. commonName: key.KeyID(),
  75. domains: domains,
  76. ipAddresses: ipAddresses,
  77. serverAuth: true,
  78. }
  79. return generateCert(key.PublicKey(), key, info, info)
  80. }
  81. // GenerateSelfSignedClientCert creates a self-signed certificate for the
  82. // given key which is to be used for TLS clients.
  83. func GenerateSelfSignedClientCert(key PrivateKey) (*x509.Certificate, error) {
  84. info := &certTemplateInfo{
  85. commonName: key.KeyID(),
  86. clientAuth: true,
  87. }
  88. return generateCert(key.PublicKey(), key, info, info)
  89. }
  90. // GenerateCACert creates a certificate which can be used as a trusted
  91. // certificate authority.
  92. func GenerateCACert(signer PrivateKey, trustedKey PublicKey) (*x509.Certificate, error) {
  93. subjectInfo := &certTemplateInfo{
  94. commonName: trustedKey.KeyID(),
  95. isCA: true,
  96. }
  97. issuerInfo := &certTemplateInfo{
  98. commonName: signer.KeyID(),
  99. }
  100. return generateCert(trustedKey, signer, subjectInfo, issuerInfo)
  101. }
  102. // GenerateCACertPool creates a certificate authority pool to be used for a
  103. // TLS configuration. Any self-signed certificates issued by the specified
  104. // trusted keys will be verified during a TLS handshake
  105. func GenerateCACertPool(signer PrivateKey, trustedKeys []PublicKey) (*x509.CertPool, error) {
  106. certPool := x509.NewCertPool()
  107. for _, trustedKey := range trustedKeys {
  108. cert, err := GenerateCACert(signer, trustedKey)
  109. if err != nil {
  110. return nil, fmt.Errorf("failed to generate CA certificate: %s", err)
  111. }
  112. certPool.AddCert(cert)
  113. }
  114. return certPool, nil
  115. }
  116. // LoadCertificateBundle loads certificates from the given file. The file should be pem encoded
  117. // containing one or more certificates. The expected pem type is "CERTIFICATE".
  118. func LoadCertificateBundle(filename string) ([]*x509.Certificate, error) {
  119. b, err := ioutil.ReadFile(filename)
  120. if err != nil {
  121. return nil, err
  122. }
  123. certificates := []*x509.Certificate{}
  124. var block *pem.Block
  125. block, b = pem.Decode(b)
  126. for ; block != nil; block, b = pem.Decode(b) {
  127. if block.Type == "CERTIFICATE" {
  128. cert, err := x509.ParseCertificate(block.Bytes)
  129. if err != nil {
  130. return nil, err
  131. }
  132. certificates = append(certificates, cert)
  133. } else {
  134. return nil, fmt.Errorf("invalid pem block type: %s", block.Type)
  135. }
  136. }
  137. return certificates, nil
  138. }
  139. // LoadCertificatePool loads a CA pool from the given file. The file should be pem encoded
  140. // containing one or more certificates. The expected pem type is "CERTIFICATE".
  141. func LoadCertificatePool(filename string) (*x509.CertPool, error) {
  142. certs, err := LoadCertificateBundle(filename)
  143. if err != nil {
  144. return nil, err
  145. }
  146. pool := x509.NewCertPool()
  147. for _, cert := range certs {
  148. pool.AddCert(cert)
  149. }
  150. return pool, nil
  151. }