github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/cloudflare/cfssl/cli/cli.go (about) 1 // Package cli provides the template for adding new cfssl commands 2 package cli 3 4 /* 5 cfssl is the command line tool to issue/sign/bundle client certificate. It's 6 also a tool to start a HTTP server to handle web requests for signing, bundling 7 and verification. 8 9 Usage: 10 cfssl command [-flags] arguments 11 12 The commands are defined in the cli subpackages and include 13 14 bundle create a certificate bundle 15 sign signs a certificate signing request (CSR) 16 serve starts a HTTP server handling sign and bundle requests 17 version prints the current cfssl version 18 genkey generates a key and an associated CSR 19 gencert generates a key and a signed certificate 20 gencsr generates a certificate request 21 selfsign generates a self-signed certificate 22 ocspsign signs an OCSP response 23 24 Use "cfssl [command] -help" to find out more about a command. 25 */ 26 27 import ( 28 "encoding/base64" 29 "encoding/json" 30 "errors" 31 "flag" 32 "fmt" 33 "io/ioutil" 34 "os" 35 36 "github.com/hellobchain/third_party/cloudflare/cfssl/config" 37 ) 38 39 // Command holds the implementation details of a cfssl command. 40 type Command struct { 41 // The Usage Text 42 UsageText string 43 // Flags to look up in the global table 44 Flags []string 45 // Main runs the command, args are the arguments after flags 46 Main func(args []string, c Config) error 47 } 48 49 var cmdName string 50 51 // usage is the cfssl usage heading. It will be appended with names of defined commands in cmds 52 // to form the final usage message of cfssl. 53 const usage = `Usage: 54 Available commands: 55 ` 56 57 // printDefaultValue is a helper function to print out a user friendly 58 // usage message of a flag. It's useful since we want to write customized 59 // usage message on selected subsets of the global flag set. It is 60 // borrowed from standard library source code. Since flag value type is 61 // not exported, default string flag values are printed without 62 // quotes. The only exception is the empty string, which is printed as "". 63 func printDefaultValue(f *flag.Flag) { 64 format := " -%s=%s: %s\n" 65 if f.DefValue == "" { 66 format = " -%s=%q: %s\n" 67 } 68 fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage) 69 } 70 71 // PopFirstArgument returns the first element and the rest of a string 72 // slice and return error if failed to do so. It is a helper function 73 // to parse non-flag arguments previously used in cfssl commands. 74 func PopFirstArgument(args []string) (string, []string, error) { 75 if len(args) < 1 { 76 return "", nil, errors.New("not enough arguments are supplied --- please refer to the usage") 77 } 78 return args[0], args[1:], nil 79 } 80 81 // Start is the entrance point of cfssl command line tools. 82 func Start(cmds map[string]*Command) error { 83 // cfsslFlagSet is the flag sets for cfssl. 84 var cfsslFlagSet = flag.NewFlagSet("cfssl", flag.ExitOnError) 85 var c Config 86 87 registerFlags(&c, cfsslFlagSet) 88 // Initial parse of command line arguments. By convention, only -h/-help is supported. 89 if flag.Usage == nil { 90 flag.Usage = func() { 91 fmt.Fprintf(os.Stderr, usage) 92 for name := range cmds { 93 fmt.Fprintf(os.Stderr, "\t%s\n", name) 94 } 95 fmt.Fprintf(os.Stderr, "Top-level flags:\n") 96 flag.PrintDefaults() 97 } 98 } 99 100 flag.Parse() 101 102 if flag.NArg() < 1 { 103 fmt.Fprintf(os.Stderr, "No command is given.\n") 104 flag.Usage() 105 return errors.New("no command was given") 106 } 107 108 // Clip out the command name and args for the command 109 cmdName = flag.Arg(0) 110 args := flag.Args()[1:] 111 cmd, found := cmds[cmdName] 112 if !found { 113 fmt.Fprintf(os.Stderr, "Command %s is not defined.\n", cmdName) 114 flag.Usage() 115 return errors.New("undefined command") 116 } 117 // always have flag 'loglevel' for each command 118 cmd.Flags = append(cmd.Flags, "loglevel") 119 // The usage of each individual command is re-written to mention 120 // flags defined and referenced only in that command. 121 cfsslFlagSet.Usage = func() { 122 fmt.Fprintf(os.Stderr, "\t%s", cmd.UsageText) 123 for _, name := range cmd.Flags { 124 if f := cfsslFlagSet.Lookup(name); f != nil { 125 printDefaultValue(f) 126 } 127 } 128 } 129 130 // Parse all flags and take the rest as argument lists for the command 131 cfsslFlagSet.Parse(args) 132 args = cfsslFlagSet.Args() 133 134 var err error 135 if c.ConfigFile != "" { 136 c.CFG, err = config.LoadFile(c.ConfigFile) 137 if err != nil { 138 fmt.Fprintf(os.Stderr, "Failed to load config file: %v", err) 139 return errors.New("failed to load config file") 140 } 141 } 142 143 if err := cmd.Main(args, c); err != nil { 144 fmt.Fprintln(os.Stderr, err) 145 return err 146 } 147 148 return nil 149 } 150 151 // ReadStdin reads from stdin if the file is "-" 152 func ReadStdin(filename string) ([]byte, error) { 153 if filename == "-" { 154 return ioutil.ReadAll(os.Stdin) 155 } 156 return ioutil.ReadFile(filename) 157 } 158 159 // PrintCert outputs a cert, key and csr to stdout 160 func PrintCert(key, csrBytes, cert []byte) { 161 out := map[string]string{} 162 if cert != nil { 163 out["cert"] = string(cert) 164 } 165 166 if key != nil { 167 out["key"] = string(key) 168 } 169 170 if csrBytes != nil { 171 out["csr"] = string(csrBytes) 172 } 173 174 jsonOut, err := json.Marshal(out) 175 if err != nil { 176 return 177 } 178 fmt.Printf("%s\n", jsonOut) 179 } 180 181 // PrintOCSPResponse outputs an OCSP response to stdout 182 // ocspResponse is base64 encoded 183 func PrintOCSPResponse(resp []byte) { 184 b64Resp := base64.StdEncoding.EncodeToString(resp) 185 186 out := map[string]string{"ocspResponse": b64Resp} 187 jsonOut, err := json.Marshal(out) 188 if err != nil { 189 return 190 } 191 fmt.Printf("%s\n", jsonOut) 192 } 193 194 // PrintCRL outputs the CRL to stdout 195 func PrintCRL(certList []byte) { 196 b64Resp := base64.StdEncoding.EncodeToString(certList) 197 198 fmt.Printf("%s\n", b64Resp) 199 }