cfssljson.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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/ioutil"
  10. "os"
  11. "github.com/cloudflare/cfssl/cli/version"
  12. )
  13. func readFile(filespec string) ([]byte, error) {
  14. if filespec == "-" {
  15. return ioutil.ReadAll(os.Stdin)
  16. }
  17. return ioutil.ReadFile(filespec)
  18. }
  19. func writeFile(filespec, contents string, perms os.FileMode) {
  20. err := ioutil.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 contents, ok := input["bundle"].(map[string]interface{}); ok {
  138. if certificateBundle, ok := contents["bundle"].(string); ok {
  139. if rootCertificate, ok := contents["root"].(string); ok {
  140. outs = append(outs, outputFile{
  141. Filename: baseName + "-bundle.pem",
  142. Contents: certificateBundle + "\n" + rootCertificate,
  143. Perms: 0644,
  144. })
  145. outs = append(outs, outputFile{
  146. Filename: baseName + "-root.pem",
  147. Contents: rootCertificate,
  148. Perms: 0644,
  149. })
  150. } else {
  151. fmt.Printf("root parsing failed!")
  152. os.Exit(200)
  153. }
  154. } else {
  155. fmt.Printf("inner bundle parsing failed!")
  156. os.Exit(200)
  157. }
  158. }
  159. if contents, ok := input["ocspResponse"]; ok {
  160. //ocspResponse is base64 encoded
  161. resp, err := base64.StdEncoding.DecodeString(contents.(string))
  162. if err != nil {
  163. fmt.Fprintf(os.Stderr, "Failed to parse ocspResponse: %v\n", err)
  164. os.Exit(1)
  165. }
  166. outs = append(outs, outputFile{
  167. Filename: baseName + "-response.der",
  168. Contents: string(resp),
  169. IsBinary: true,
  170. Perms: 0644,
  171. })
  172. }
  173. for _, e := range outs {
  174. if *output {
  175. if e.IsBinary {
  176. e.Contents = base64.StdEncoding.EncodeToString([]byte(e.Contents))
  177. }
  178. fmt.Fprintf(os.Stdout, "%s\n", e.Contents)
  179. } else {
  180. writeFile(e.Filename, e.Contents, e.Perms)
  181. }
  182. }
  183. }