github.com/brimstone/sbuca@v0.0.0-20151202175429-8691d9eba5c5/sbuca.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"net/url"
     9  	"os"
    10  	"strings"
    11  
    12  	"github.com/brimstone/sbuca/pkix"
    13  	"github.com/brimstone/sbuca/server"
    14  	"github.com/codegangsta/cli"
    15  )
    16  
    17  func main() {
    18  
    19  	app := cli.NewApp()
    20  	app.Name = "sbuca"
    21  	app.Usage = "Simple But Useful CA"
    22  	app.Commands = []cli.Command{
    23  
    24  		{
    25  			Name:  "server",
    26  			Usage: "Run a CA server",
    27  			Flags: []cli.Flag{
    28  				cli.StringFlag{
    29  					Name:  "dir",
    30  					Value: ".",
    31  					Usage: "Root directory for certificates",
    32  				},
    33  				cli.StringFlag{
    34  					Name:  "address",
    35  					Value: os.Getenv("HOST") + ":8600",
    36  					Usage: "Token for cert signing functions",
    37  				},
    38  				cli.StringFlag{
    39  					Name:  "admin-token",
    40  					Value: "",
    41  					Usage: "Token for administrative functions",
    42  				},
    43  				cli.StringFlag{
    44  					Name:  "sign-token",
    45  					Value: "",
    46  					Usage: "Token for cert signing functions",
    47  				},
    48  			},
    49  			Action: func(c *cli.Context) {
    50  				config := map[string]string{
    51  					"address":     c.String("address"),
    52  					"root-dir":    c.String("dir"),
    53  					"admin-token": c.String("admin-token"),
    54  					"sign-token":  c.String("sign-token"),
    55  				}
    56  				server.Run(config)
    57  			},
    58  		},
    59  
    60  		{
    61  			Name:  "genkey",
    62  			Usage: "Generate a RSA Private Key to STDOUT",
    63  			Action: func(c *cli.Context) {
    64  				key, err := pkix.NewKey()
    65  				if err != nil {
    66  					panic(err)
    67  				}
    68  
    69  				pem, err := key.ToPEM()
    70  				if err != nil {
    71  					panic(err)
    72  				}
    73  
    74  				fmt.Print(string(pem))
    75  			},
    76  		},
    77  
    78  		{
    79  			Name:  "gencsr",
    80  			Usage: "Generate a Certificate Request to STDOUT",
    81  			Flags: []cli.Flag{
    82  				cli.StringFlag{
    83  					Name:  "key",
    84  					Usage: "RSA Private Key",
    85  				},
    86  			},
    87  			Action: func(c *cli.Context) {
    88  				keyName := c.String("key")
    89  				if keyName == "" {
    90  					fmt.Fprintln(os.Stderr, "[ERROR] Requere private key as parameter")
    91  					return
    92  				}
    93  
    94  				key, err := pkix.NewKeyFromPrivateKeyPEMFile(keyName)
    95  				if err != nil {
    96  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to generate CSR: "+err.Error())
    97  					return
    98  				}
    99  
   100  				csr, err := pkix.NewCertificateRequest(key)
   101  				if err != nil {
   102  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to generate CSR: "+err.Error())
   103  					return
   104  				}
   105  
   106  				pem, err := csr.ToPEM()
   107  				if err != nil {
   108  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to generate CSR: "+err.Error())
   109  					return
   110  				}
   111  
   112  				fmt.Print(string(pem))
   113  			},
   114  		},
   115  
   116  		{
   117  			Name:  "submitcsr",
   118  			Usage: "Submit a Certificate Request to CA",
   119  			Flags: []cli.Flag{
   120  				cli.StringFlag{
   121  					Name:  "host",
   122  					Usage: "Host ip & port",
   123  				},
   124  				cli.StringFlag{
   125  					Name:  "format",
   126  					Value: "cert",
   127  					Usage: "output cert or id",
   128  				},
   129  				cli.StringFlag{
   130  					Name:  "token",
   131  					Usage: "Authorization Token",
   132  				},
   133  			},
   134  			Action: func(c *cli.Context) {
   135  				host := c.String("host")
   136  				if host == "" {
   137  					fmt.Fprintln(os.Stderr, "[ERROR] Requere host as parameter")
   138  					return
   139  				}
   140  
   141  				format := c.String("format")
   142  				if format != "cert" && format != "id" {
   143  					fmt.Fprintln(os.Stderr, "[ERROR] format should be 'cert' or 'id'")
   144  					return
   145  				}
   146  
   147  				args := c.Args()
   148  				if len(args) == 0 {
   149  					fmt.Fprintln(os.Stderr, "[ERROR] Should provide csr")
   150  					return
   151  				}
   152  				csrName := c.Args().First()
   153  
   154  				csr, err := pkix.NewCertificateRequestFromPEMFile(csrName)
   155  				if err != nil {
   156  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to parse CSR: "+err.Error())
   157  					return
   158  				}
   159  
   160  				//resp, err := http.Post("http://example.com/upload", "application/json", &buf)
   161  				//var data interface{}
   162  				pem, err := csr.ToPEM()
   163  				if err != nil {
   164  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to parse CSR: "+err.Error())
   165  					return
   166  				}
   167  
   168  				data := make(url.Values)
   169  				data.Add("csr", string(pem))
   170  
   171  				//resp, err := http.PostForm("http://"+host+"/certificates", data)
   172  				client := &http.Client{}
   173  				req, _ := http.NewRequest("POST", "http://"+host+"/certificates", strings.NewReader(data.Encode()))
   174  				req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   175  				if c.String("token") != "" {
   176  					req.Header.Set("X-API-KEY", c.String("token"))
   177  				}
   178  				resp, err := client.Do(req)
   179  				if err != nil {
   180  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to request: "+err.Error())
   181  					return
   182  				}
   183  				decoder := json.NewDecoder(resp.Body)
   184  				respData := make(map[string]map[string]interface{})
   185  				if err := decoder.Decode(&respData); err != nil {
   186  					panic(err)
   187  				}
   188  
   189  				if format == "cert" {
   190  					fmt.Print(respData["certificate"]["crt"])
   191  				}
   192  				if format == "id" {
   193  					fmt.Println(respData["certificate"]["id"])
   194  				}
   195  			},
   196  		},
   197  
   198  		{
   199  			Name: "getcrt",
   200  			Flags: []cli.Flag{
   201  				cli.StringFlag{
   202  					Name:  "host",
   203  					Usage: "Host ip & port",
   204  				},
   205  			},
   206  			Usage: "Get a Certificate from CA and output to STDOUT",
   207  			Action: func(c *cli.Context) {
   208  
   209  				host := c.String("host")
   210  				if host == "" {
   211  					fmt.Fprintln(os.Stderr, "[ERROR] Requere host as parameter")
   212  					return
   213  				}
   214  
   215  				args := c.Args()
   216  				if len(args) == 0 {
   217  					fmt.Fprintln(os.Stderr, "[ERROR] Should provide id (same as serial number)")
   218  					return
   219  				}
   220  				id := c.Args().First()
   221  
   222  				resp, err := http.Get("http://" + host + "/certificates/" + id)
   223  				if err != nil {
   224  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to request: "+err.Error())
   225  					return
   226  				}
   227  
   228  				decoder := json.NewDecoder(resp.Body)
   229  				respData := make(map[string]map[string]interface{})
   230  				if err := decoder.Decode(&respData); err != nil {
   231  					panic(err)
   232  				}
   233  
   234  				fmt.Print(respData["certificate"]["crt"])
   235  
   236  			},
   237  		},
   238  
   239  		{
   240  			Name: "getcacrt",
   241  			Flags: []cli.Flag{
   242  				cli.StringFlag{
   243  					Name:  "host",
   244  					Usage: "Host ip & port",
   245  				},
   246  			},
   247  			Usage: "Get CA's Certificate and output to STDOUT",
   248  			Action: func(c *cli.Context) {
   249  
   250  				host := c.String("host")
   251  				if host == "" {
   252  					fmt.Fprintln(os.Stderr, "[ERROR] Require host as parameter")
   253  					return
   254  				}
   255  
   256  				resp, err := http.Get("http://" + host + "/ca/certificate")
   257  				if err != nil {
   258  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to request CA cert: "+err.Error())
   259  					os.Exit(1)
   260  				}
   261  
   262  				decoder := json.NewDecoder(resp.Body)
   263  				if resp.StatusCode != 200 {
   264  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to request CA cert: "+resp.Status)
   265  					os.Exit(resp.StatusCode)
   266  				}
   267  				respData := make(map[string]map[string]interface{})
   268  				if err := decoder.Decode(&respData); err != nil {
   269  					panic(err)
   270  				}
   271  
   272  				fmt.Print(respData["ca"]["crt"])
   273  
   274  			},
   275  		},
   276  		{
   277  			Name: "oneshot",
   278  			Flags: []cli.Flag{
   279  				cli.StringFlag{
   280  					Name:  "host",
   281  					Usage: "Host ip & port",
   282  				},
   283  				cli.StringFlag{
   284  					Name:  "key",
   285  					Usage: "Path to private key file",
   286  				},
   287  				cli.StringFlag{
   288  					Name:  "crt",
   289  					Usage: "Path to public cert file",
   290  				},
   291  				cli.StringFlag{
   292  					Name:  "ca",
   293  					Usage: "Path to public ca file",
   294  				},
   295  				cli.StringFlag{
   296  					Name:  "token",
   297  					Usage: "Authorization Token",
   298  				},
   299  			},
   300  			Usage: "Generate key, request, and submit to a server, all in one shot",
   301  			Action: func(c *cli.Context) {
   302  				keypath := c.String("key")
   303  				if keypath == "" {
   304  					fmt.Fprintln(os.Stderr, "Path to private key required")
   305  					return
   306  				}
   307  				crtpath := c.String("crt")
   308  				if crtpath == "" {
   309  					fmt.Fprintln(os.Stderr, "Path to public certificate required")
   310  					return
   311  				}
   312  				capath := c.String("ca")
   313  				if capath == "" {
   314  					fmt.Fprintln(os.Stderr, "Path to central authority required")
   315  					return
   316  				}
   317  				host := c.String("host")
   318  				if host == "" {
   319  					fmt.Fprintln(os.Stderr, "Location of host required")
   320  					return
   321  				}
   322  				keyfile, err := os.Create(keypath)
   323  				if err != nil {
   324  					fmt.Println(err)
   325  					os.Exit(1)
   326  				}
   327  				defer keyfile.Close()
   328  
   329  				crtfile, err := os.Create(crtpath)
   330  				if err != nil {
   331  					fmt.Println(err)
   332  					os.Exit(1)
   333  				}
   334  				defer crtfile.Close()
   335  
   336  				cafile, err := os.Create(capath)
   337  				if err != nil {
   338  					fmt.Println(err)
   339  					os.Exit(1)
   340  				}
   341  				defer cafile.Close()
   342  
   343  				// genkey
   344  				key, err := pkix.NewKey()
   345  				if err != nil {
   346  					fmt.Println(err)
   347  					os.Exit(1)
   348  				}
   349  
   350  				pem, err := key.ToPEM()
   351  				if err != nil {
   352  					fmt.Println(err)
   353  					os.Exit(1)
   354  				}
   355  
   356  				n, err := io.WriteString(keyfile, string(pem))
   357  				if err != nil {
   358  					fmt.Println(n, err)
   359  				}
   360  				fmt.Println("Key written to", keypath)
   361  
   362  				// gencsr
   363  				csr, err := pkix.NewCertificateRequest(key)
   364  				if err != nil {
   365  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to generate CSR: "+err.Error())
   366  					return
   367  				}
   368  				csrpem, err := csr.ToPEM()
   369  				// submitcsr
   370  				data := make(url.Values)
   371  				data.Add("csr", string(csrpem))
   372  
   373  				//resp, err := http.PostForm("http://"+host+"/certificates", data)
   374  				client := &http.Client{}
   375  				req, _ := http.NewRequest("POST", "http://"+host+"/certificates", strings.NewReader(data.Encode()))
   376  				req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   377  				if c.String("token") != "" {
   378  					req.Header.Set("X-API-KEY", c.String("token"))
   379  				}
   380  				resp, err := client.Do(req)
   381  				if err != nil {
   382  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to request: "+err.Error())
   383  					return
   384  				}
   385  				decoder := json.NewDecoder(resp.Body)
   386  				respData := make(map[string]map[string]interface{})
   387  				if err := decoder.Decode(&respData); err != nil {
   388  					panic(err)
   389  				}
   390  
   391  				n, err = io.WriteString(crtfile, string(respData["certificate"]["crt"].(string)))
   392  				if err != nil {
   393  					fmt.Println(n, err)
   394  				}
   395  				fmt.Println("Certificate written to", crtpath)
   396  
   397  				// getcacrt
   398  				resp, err = http.Get("http://" + host + "/ca/certificate")
   399  				if err != nil {
   400  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to request CA cert: "+err.Error())
   401  					os.Exit(1)
   402  				}
   403  
   404  				decoder = json.NewDecoder(resp.Body)
   405  				if resp.StatusCode != 200 {
   406  					fmt.Fprintln(os.Stderr, "[ERROR] Failed to request CA cert: "+resp.Status)
   407  					os.Exit(resp.StatusCode)
   408  				}
   409  				respData = make(map[string]map[string]interface{})
   410  				if err := decoder.Decode(&respData); err != nil {
   411  					panic(err)
   412  				}
   413  
   414  				n, err = io.WriteString(cafile, string(respData["ca"]["crt"].(string)))
   415  				if err != nil {
   416  					fmt.Println(n, err)
   417  				}
   418  				fmt.Println("Certificate Authority written to", capath)
   419  			},
   420  		},
   421  	}
   422  
   423  	app.Run(os.Args)
   424  
   425  }