selfsign.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // Package selfsign implements certificate selfsigning. This is very
  2. // dangerous and should never be used in production.
  3. package selfsign
  4. import (
  5. "crypto"
  6. "crypto/rand"
  7. "crypto/sha1"
  8. "crypto/x509"
  9. "crypto/x509/pkix"
  10. "encoding/asn1"
  11. "encoding/pem"
  12. "errors"
  13. "math"
  14. "math/big"
  15. "time"
  16. "github.com/cloudflare/cfssl/config"
  17. cferr "github.com/cloudflare/cfssl/errors"
  18. "github.com/cloudflare/cfssl/helpers"
  19. "github.com/cloudflare/cfssl/signer"
  20. )
  21. const threeMonths = 2190 * time.Hour
  22. // parseCertificateRequest takes an incoming certificate request and
  23. // builds a certificate template from it.
  24. func parseCertificateRequest(priv crypto.Signer, csrBytes []byte) (template *x509.Certificate, err error) {
  25. csr, err := x509.ParseCertificateRequest(csrBytes)
  26. if err != nil {
  27. err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
  28. return
  29. }
  30. err = helpers.CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature)
  31. if err != nil {
  32. err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
  33. return
  34. }
  35. template = &x509.Certificate{
  36. Subject: csr.Subject,
  37. PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
  38. PublicKey: csr.PublicKey,
  39. SignatureAlgorithm: signer.DefaultSigAlgo(priv),
  40. }
  41. return
  42. }
  43. type subjectPublicKeyInfo struct {
  44. Algorithm pkix.AlgorithmIdentifier
  45. SubjectPublicKey asn1.BitString
  46. }
  47. // Sign creates a new self-signed certificate.
  48. func Sign(priv crypto.Signer, csrPEM []byte, profile *config.SigningProfile) ([]byte, error) {
  49. if profile == nil {
  50. return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("no profile for self-signing"))
  51. }
  52. p, _ := pem.Decode(csrPEM)
  53. if p == nil || p.Type != "CERTIFICATE REQUEST" {
  54. return nil, cferr.New(cferr.CSRError, cferr.BadRequest)
  55. }
  56. template, err := parseCertificateRequest(priv, p.Bytes)
  57. if err != nil {
  58. return nil, err
  59. }
  60. pub := template.PublicKey
  61. encodedpub, err := x509.MarshalPKIXPublicKey(pub)
  62. if err != nil {
  63. return nil, err
  64. }
  65. var subPKI subjectPublicKeyInfo
  66. _, err = asn1.Unmarshal(encodedpub, &subPKI)
  67. if err != nil {
  68. return nil, err
  69. }
  70. pubhash := sha1.New()
  71. pubhash.Write(subPKI.SubjectPublicKey.Bytes)
  72. var (
  73. eku []x509.ExtKeyUsage
  74. ku x509.KeyUsage
  75. expiry time.Duration
  76. crlURL, ocspURL string
  77. )
  78. // The third value returned from Usages is a list of unknown key usages.
  79. // This should be used when validating the profile at load, and isn't used
  80. // here.
  81. ku, eku, _ = profile.Usages()
  82. expiry = profile.Expiry
  83. if ku == 0 && len(eku) == 0 {
  84. err = cferr.New(cferr.PolicyError, cferr.NoKeyUsages)
  85. return nil, err
  86. }
  87. if expiry == 0 {
  88. expiry = threeMonths
  89. }
  90. now := time.Now()
  91. serialNumber, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
  92. if err != nil {
  93. err = cferr.Wrap(cferr.CSRError, cferr.Unknown, err)
  94. return nil, err
  95. }
  96. template.SerialNumber = serialNumber
  97. template.NotBefore = now.Add(-5 * time.Minute).UTC()
  98. template.NotAfter = now.Add(expiry).UTC()
  99. template.KeyUsage = ku
  100. template.ExtKeyUsage = eku
  101. template.BasicConstraintsValid = true
  102. template.IsCA = profile.CAConstraint.IsCA
  103. template.SubjectKeyId = pubhash.Sum(nil)
  104. if ocspURL != "" {
  105. template.OCSPServer = []string{ocspURL}
  106. }
  107. if crlURL != "" {
  108. template.CRLDistributionPoints = []string{crlURL}
  109. }
  110. if len(profile.IssuerURL) != 0 {
  111. template.IssuingCertificateURL = profile.IssuerURL
  112. }
  113. cert, err := x509.CreateCertificate(rand.Reader, template, template, pub, priv)
  114. if err != nil {
  115. return nil, err
  116. }
  117. cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert})
  118. return cert, nil
  119. }