kubernetes/vendor/github.com/cloudflare/cfssl/cmd/cfssljson/cfssljson.go
2018-08-08 21:01:29 -07:00

212 lines
4.9 KiB
Go

// cfssljson splits out JSON with cert, csr, and key fields to separate
// files.
package main
import (
"encoding/base64"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"github.com/cloudflare/cfssl/cli/version"
)
func readFile(filespec string) ([]byte, error) {
if filespec == "-" {
return ioutil.ReadAll(os.Stdin)
}
return ioutil.ReadFile(filespec)
}
func writeFile(filespec, contents string, perms os.FileMode) {
err := ioutil.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)
}
}
}