command line tool to make self signed x.509 CA and cert for a domain
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
4.4 KiB

9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
  1. package main
  2. import (
  3. "crypto/x509"
  4. "crypto/x509/pkix"
  5. "encoding/pem"
  6. "fmt"
  7. "log"
  8. "os"
  9. "path/filepath"
  10. "time"
  11. "git.sequentialread.com/forest/easypki.git/pkg/certificate"
  12. "git.sequentialread.com/forest/easypki.git/pkg/easypki"
  13. "git.sequentialread.com/forest/easypki.git/pkg/store"
  14. errors "git.sequentialread.com/forest/pkg-errors"
  15. )
  16. func main() {
  17. domain := os.Args[1]
  18. outputLocation, err := os.Getwd()
  19. if err != nil {
  20. log.Fatal(err)
  21. }
  22. inMemoryStore := &store.InMemory{}
  23. pki := &easypki.EasyPKI{Store: inMemoryStore}
  24. domainCA := fmt.Sprintf("%s_CA", domain)
  25. log.Println("make-fake-cert: creating server CA / key pair ")
  26. // Create a CA for the server's key/cert
  27. err = pki.Sign(
  28. nil,
  29. &easypki.Request{
  30. Name: domainCA,
  31. Template: &x509.Certificate{
  32. NotAfter: time.Now().Add(time.Hour * 24 * 720),
  33. IsCA: true,
  34. MaxPathLen: -1,
  35. Subject: getSubject(domainCA),
  36. },
  37. },
  38. )
  39. if err != nil {
  40. panic(errors.Wrap(err, "make-fake-cert: failed creating CA"))
  41. }
  42. err = saveBundle(pki, domainCA, domainCA, false, outputLocation)
  43. if err != nil {
  44. panic(errors.Wrap(err, "make-fake-cert: saveBundle():"))
  45. }
  46. caSigner, err := pki.GetCA(domainCA)
  47. if err != nil {
  48. panic(errors.Wrap(err, "make-fake-cert: signer named \"CA\" was not found"))
  49. }
  50. // Create server certificate
  51. err = pki.Sign(
  52. caSigner,
  53. &easypki.Request{
  54. Name: domain,
  55. Template: &x509.Certificate{
  56. NotAfter: time.Now().Add(time.Hour * 24 * 720),
  57. IsCA: false,
  58. Subject: getSubject(domain),
  59. DNSNames: []string{domain},
  60. },
  61. },
  62. )
  63. if err != nil {
  64. panic(errors.Wrap(err, "make-fake-cert: failed creating Threshold server certificate"))
  65. }
  66. err = saveBundle(pki, domainCA, domain, true, outputLocation)
  67. if err != nil {
  68. panic(errors.Wrap(err, "make-fake-cert: saveBundle():"))
  69. }
  70. if len(os.Args) == 3 {
  71. user := fmt.Sprintf("%s@%s", os.Args[2], domain)
  72. // Create client certificate
  73. err = pki.Sign(
  74. caSigner,
  75. &easypki.Request{
  76. Name: user,
  77. Template: &x509.Certificate{
  78. NotAfter: time.Now().Add(time.Hour * 24 * 720),
  79. IsCA: false,
  80. Subject: getSubject(user),
  81. EmailAddresses: []string{user},
  82. },
  83. },
  84. )
  85. if err != nil {
  86. panic(errors.Wrap(err, "make-fake-cert: failed creating Threshold server certificate"))
  87. }
  88. err = saveBundle(pki, domainCA, user, true, outputLocation)
  89. if err != nil {
  90. panic(errors.Wrap(err, "make-fake-cert: saveBundle():"))
  91. }
  92. }
  93. }
  94. func saveBundle(pki *easypki.EasyPKI, caName, bundleName string, savePrivateKey bool, saveInDirectory string) error {
  95. var bundle *certificate.Bundle
  96. if caName == "" {
  97. caName = bundleName
  98. }
  99. bundle, err := pki.GetBundle(caName, bundleName)
  100. if err != nil {
  101. panic(errors.Wrapf(err, "Failed getting bundle %v within CA %v: %v", bundleName, caName))
  102. }
  103. leaf := bundle
  104. chain := []*certificate.Bundle{bundle}
  105. //if fullChain {
  106. for {
  107. if leaf.Cert.Issuer.CommonName == leaf.Cert.Subject.CommonName {
  108. break
  109. }
  110. ca, err := pki.GetCA(leaf.Cert.Issuer.CommonName)
  111. if err != nil {
  112. panic(errors.Wrapf(err, "Failed getting signing CA %v: %v", leaf.Cert.Issuer.CommonName))
  113. }
  114. chain = append(chain, ca)
  115. leaf = ca
  116. }
  117. //}
  118. if savePrivateKey {
  119. key, err := os.Create(filepath.Join(saveInDirectory, bundleName+".key"))
  120. if err != nil {
  121. panic(errors.Wrap(err, "Failed creating key output file"))
  122. }
  123. if err := pem.Encode(key, &pem.Block{
  124. Bytes: x509.MarshalPKCS1PrivateKey(bundle.Key),
  125. Type: "RSA PRIVATE KEY",
  126. }); err != nil {
  127. panic(errors.Wrap(err, "Failed ecoding private key"))
  128. }
  129. }
  130. crtName := bundleName + ".crt"
  131. cert, err := os.Create(filepath.Join(saveInDirectory, crtName))
  132. if err != nil {
  133. panic(errors.Wrap(err, "Failed creating chain output file"))
  134. }
  135. for _, c := range chain {
  136. if err := pem.Encode(cert, &pem.Block{
  137. Bytes: c.Cert.Raw,
  138. Type: "CERTIFICATE",
  139. }); err != nil {
  140. panic(errors.Wrapf(err, "Failed ecoding %v certificate: %v", c.Name))
  141. }
  142. }
  143. return nil
  144. }
  145. // TODO add certificate metadata option to seedpacket?
  146. func getSubject(commonName string) pkix.Name {
  147. return pkix.Name{
  148. Organization: []string{"aaaaa user left blank"},
  149. OrganizationalUnit: []string{"aaaaa user left blank"},
  150. Locality: []string{"aaaaa user left blank"},
  151. Country: []string{"aaaaa user left blank"},
  152. Province: []string{"aaaaa user left blank"},
  153. CommonName: commonName,
  154. }
  155. }