123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- // cfssljson splits out JSON with cert, csr, and key fields to separate
- // files.
- package main
- import (
- "encoding/base64"
- "encoding/json"
- "flag"
- "fmt"
- "io"
- "os"
- "github.com/cloudflare/cfssl/cli/version"
- )
- func readFile(filespec string) ([]byte, error) {
- if filespec == "-" {
- return io.ReadAll(os.Stdin)
- }
- return os.ReadFile(filespec)
- }
- func writeFile(filespec, contents string, perms os.FileMode) {
- err := os.WriteFile(filespec, []byte(contents), perms)
- if err != nil {
- fmt.Fprintf(os.Stderr, "%v\n", err)
- os.Exit(1)
- }
- }
- // ResponseMessage represents the format of a CFSSL output for an error or message
- type ResponseMessage struct {
- Code int `json:"int"`
- Message string `json:"message"`
- }
- // Response represents the format of a CFSSL output
- type Response struct {
- Success bool `json:"success"`
- Result map[string]interface{} `json:"result"`
- Errors []ResponseMessage `json:"errors"`
- Messages []ResponseMessage `json:"messages"`
- }
- type outputFile struct {
- Filename string
- Contents string
- IsBinary bool
- Perms os.FileMode
- }
- func main() {
- bare := flag.Bool("bare", false, "the response from CFSSL is not wrapped in the API standard response")
- inFile := flag.String("f", "-", "JSON input")
- output := flag.Bool("stdout", false, "output the response instead of saving to a file")
- printVersion := flag.Bool("version", false, "print version and exit")
- flag.Parse()
- if *printVersion {
- fmt.Printf("%s", version.FormatVersion())
- return
- }
- var baseName string
- if flag.NArg() == 0 {
- baseName = "cert"
- } else {
- baseName = flag.Arg(0)
- }
- var input = map[string]interface{}{}
- var outs []outputFile
- var cert string
- var key string
- var csr string
- fileData, err := readFile(*inFile)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to read input: %v\n", err)
- os.Exit(1)
- }
- if *bare {
- err = json.Unmarshal(fileData, &input)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to parse input: %v\n", err)
- os.Exit(1)
- }
- } else {
- var response Response
- err = json.Unmarshal(fileData, &response)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to parse input: %v\n", err)
- os.Exit(1)
- }
- if !response.Success {
- fmt.Fprintf(os.Stderr, "Request failed:\n")
- for _, msg := range response.Errors {
- fmt.Fprintf(os.Stderr, "\t%s\n", msg.Message)
- }
- os.Exit(1)
- }
- input = response.Result
- }
- if contents, ok := input["cert"]; ok {
- cert = contents.(string)
- } else if contents, ok = input["certificate"]; ok {
- cert = contents.(string)
- }
- if cert != "" {
- outs = append(outs, outputFile{
- Filename: baseName + ".pem",
- Contents: cert,
- Perms: 0664,
- })
- }
- if contents, ok := input["key"]; ok {
- key = contents.(string)
- } else if contents, ok = input["private_key"]; ok {
- key = contents.(string)
- }
- if key != "" {
- outs = append(outs, outputFile{
- Filename: baseName + "-key.pem",
- Contents: key,
- Perms: 0600,
- })
- }
- if contents, ok := input["encrypted_key"]; ok {
- encKey := contents.(string)
- outs = append(outs, outputFile{
- Filename: baseName + "-key.enc",
- Contents: encKey,
- IsBinary: true,
- Perms: 0600,
- })
- }
- if contents, ok := input["csr"]; ok {
- csr = contents.(string)
- } else if contents, ok = input["certificate_request"]; ok {
- csr = contents.(string)
- }
- if csr != "" {
- outs = append(outs, outputFile{
- Filename: baseName + ".csr",
- Contents: csr,
- Perms: 0644,
- })
- }
- if result, ok := input["result"].(map[string]interface{}); ok {
- if bundle, ok := result["bundle"].(map[string]interface{}); ok {
- // if we've gotten this deep then we're trying to parse out
- // a bundle, now we fail if we can't find the keys we need.
- certificateBundle, ok := bundle["bundle"].(string)
- if !ok {
- fmt.Fprintf(os.Stderr, "inner bundle parsing failed!\n")
- os.Exit(1)
- }
- rootCertificate, ok := bundle["root"].(string)
- if !ok {
- fmt.Fprintf(os.Stderr, "root parsing failed!\n")
- os.Exit(1)
- }
- outs = append(outs, outputFile{
- Filename: baseName + "-bundle.pem",
- Contents: certificateBundle + "\n" + rootCertificate,
- Perms: 0644,
- })
- outs = append(outs, outputFile{
- Filename: baseName + "-root.pem",
- Contents: rootCertificate,
- Perms: 0644,
- })
- }
- }
- if contents, ok := input["ocspResponse"]; ok {
- // ocspResponse is base64 encoded
- resp, err := base64.StdEncoding.DecodeString(contents.(string))
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to parse ocspResponse: %v\n", err)
- os.Exit(1)
- }
- outs = append(outs, outputFile{
- Filename: baseName + "-response.der",
- Contents: string(resp),
- IsBinary: true,
- Perms: 0644,
- })
- }
- for _, e := range outs {
- if *output {
- if e.IsBinary {
- e.Contents = base64.StdEncoding.EncodeToString([]byte(e.Contents))
- }
- fmt.Fprintf(os.Stdout, "%s\n", e.Contents)
- } else {
- writeFile(e.Filename, e.Contents, e.Perms)
- }
- }
- }
|