cfssljson.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // cfssljson splits out JSON with cert, csr, and key fields to separate
  2. // files.
  3. package main
  4. import (
  5. "encoding/base64"
  6. "encoding/json"
  7. "flag"
  8. "fmt"
  9. "io"
  10. "os"
  11. "github.com/cloudflare/cfssl/cli/version"
  12. )
  13. func readFile(filespec string) ([]byte, error) {
  14. if filespec == "-" {
  15. return io.ReadAll(os.Stdin)
  16. }
  17. return os.ReadFile(filespec)
  18. }
  19. func writeFile(filespec, contents string, perms os.FileMode) {
  20. err := os.WriteFile(filespec, []byte(contents), perms)
  21. if err != nil {
  22. fmt.Fprintf(os.Stderr, "%v\n", err)
  23. os.Exit(1)
  24. }
  25. }
  26. // ResponseMessage represents the format of a CFSSL output for an error or message
  27. type ResponseMessage struct {
  28. Code int `json:"int"`
  29. Message string `json:"message"`
  30. }
  31. // Response represents the format of a CFSSL output
  32. type Response struct {
  33. Success bool `json:"success"`
  34. Result map[string]interface{} `json:"result"`
  35. Errors []ResponseMessage `json:"errors"`
  36. Messages []ResponseMessage `json:"messages"`
  37. }
  38. type outputFile struct {
  39. Filename string
  40. Contents string
  41. IsBinary bool
  42. Perms os.FileMode
  43. }
  44. func main() {
  45. bare := flag.Bool("bare", false, "the response from CFSSL is not wrapped in the API standard response")
  46. inFile := flag.String("f", "-", "JSON input")
  47. output := flag.Bool("stdout", false, "output the response instead of saving to a file")
  48. printVersion := flag.Bool("version", false, "print version and exit")
  49. flag.Parse()
  50. if *printVersion {
  51. fmt.Printf("%s", version.FormatVersion())
  52. return
  53. }
  54. var baseName string
  55. if flag.NArg() == 0 {
  56. baseName = "cert"
  57. } else {
  58. baseName = flag.Arg(0)
  59. }
  60. var input = map[string]interface{}{}
  61. var outs []outputFile
  62. var cert string
  63. var key string
  64. var csr string
  65. fileData, err := readFile(*inFile)
  66. if err != nil {
  67. fmt.Fprintf(os.Stderr, "Failed to read input: %v\n", err)
  68. os.Exit(1)
  69. }
  70. if *bare {
  71. err = json.Unmarshal(fileData, &input)
  72. if err != nil {
  73. fmt.Fprintf(os.Stderr, "Failed to parse input: %v\n", err)
  74. os.Exit(1)
  75. }
  76. } else {
  77. var response Response
  78. err = json.Unmarshal(fileData, &response)
  79. if err != nil {
  80. fmt.Fprintf(os.Stderr, "Failed to parse input: %v\n", err)
  81. os.Exit(1)
  82. }
  83. if !response.Success {
  84. fmt.Fprintf(os.Stderr, "Request failed:\n")
  85. for _, msg := range response.Errors {
  86. fmt.Fprintf(os.Stderr, "\t%s\n", msg.Message)
  87. }
  88. os.Exit(1)
  89. }
  90. input = response.Result
  91. }
  92. if contents, ok := input["cert"]; ok {
  93. cert = contents.(string)
  94. } else if contents, ok = input["certificate"]; ok {
  95. cert = contents.(string)
  96. }
  97. if cert != "" {
  98. outs = append(outs, outputFile{
  99. Filename: baseName + ".pem",
  100. Contents: cert,
  101. Perms: 0664,
  102. })
  103. }
  104. if contents, ok := input["key"]; ok {
  105. key = contents.(string)
  106. } else if contents, ok = input["private_key"]; ok {
  107. key = contents.(string)
  108. }
  109. if key != "" {
  110. outs = append(outs, outputFile{
  111. Filename: baseName + "-key.pem",
  112. Contents: key,
  113. Perms: 0600,
  114. })
  115. }
  116. if contents, ok := input["encrypted_key"]; ok {
  117. encKey := contents.(string)
  118. outs = append(outs, outputFile{
  119. Filename: baseName + "-key.enc",
  120. Contents: encKey,
  121. IsBinary: true,
  122. Perms: 0600,
  123. })
  124. }
  125. if contents, ok := input["csr"]; ok {
  126. csr = contents.(string)
  127. } else if contents, ok = input["certificate_request"]; ok {
  128. csr = contents.(string)
  129. }
  130. if csr != "" {
  131. outs = append(outs, outputFile{
  132. Filename: baseName + ".csr",
  133. Contents: csr,
  134. Perms: 0644,
  135. })
  136. }
  137. if result, ok := input["result"].(map[string]interface{}); ok {
  138. if bundle, ok := result["bundle"].(map[string]interface{}); ok {
  139. // if we've gotten this deep then we're trying to parse out
  140. // a bundle, now we fail if we can't find the keys we need.
  141. certificateBundle, ok := bundle["bundle"].(string)
  142. if !ok {
  143. fmt.Fprintf(os.Stderr, "inner bundle parsing failed!\n")
  144. os.Exit(1)
  145. }
  146. rootCertificate, ok := bundle["root"].(string)
  147. if !ok {
  148. fmt.Fprintf(os.Stderr, "root parsing failed!\n")
  149. os.Exit(1)
  150. }
  151. outs = append(outs, outputFile{
  152. Filename: baseName + "-bundle.pem",
  153. Contents: certificateBundle + "\n" + rootCertificate,
  154. Perms: 0644,
  155. })
  156. outs = append(outs, outputFile{
  157. Filename: baseName + "-root.pem",
  158. Contents: rootCertificate,
  159. Perms: 0644,
  160. })
  161. }
  162. }
  163. if contents, ok := input["ocspResponse"]; ok {
  164. // ocspResponse is base64 encoded
  165. resp, err := base64.StdEncoding.DecodeString(contents.(string))
  166. if err != nil {
  167. fmt.Fprintf(os.Stderr, "Failed to parse ocspResponse: %v\n", err)
  168. os.Exit(1)
  169. }
  170. outs = append(outs, outputFile{
  171. Filename: baseName + "-response.der",
  172. Contents: string(resp),
  173. IsBinary: true,
  174. Perms: 0644,
  175. })
  176. }
  177. for _, e := range outs {
  178. if *output {
  179. if e.IsBinary {
  180. e.Contents = base64.StdEncoding.EncodeToString([]byte(e.Contents))
  181. }
  182. fmt.Fprintf(os.Stdout, "%s\n", e.Contents)
  183. } else {
  184. writeFile(e.Filename, e.Contents, e.Perms)
  185. }
  186. }
  187. }