From 867a37311c64b3c22807ee108298765b103368f5 Mon Sep 17 00:00:00 2001 From: Ruoyu Ying Date: Wed, 16 Feb 2022 20:33:43 -0500 Subject: [PATCH] Add Certificate utility for easy usage * Place cert util under /src/scc/tools Change-Id: Ia749f8104b0af123ccad7d7ff6b26acadea5b494 Signed-off-by: Ruoyu Ying --- central-controller/src/scc/tools/certctl/README | 24 ++++ .../src/scc/tools/certctl/certctl.go | 149 +++++++++++++++++++++ central-controller/src/scc/tools/certctl/go.mod | 3 + 3 files changed, 176 insertions(+) create mode 100644 central-controller/src/scc/tools/certctl/README create mode 100644 central-controller/src/scc/tools/certctl/certctl.go create mode 100644 central-controller/src/scc/tools/certctl/go.mod diff --git a/central-controller/src/scc/tools/certctl/README b/central-controller/src/scc/tools/certctl/README new file mode 100644 index 0000000..64e5218 --- /dev/null +++ b/central-controller/src/scc/tools/certctl/README @@ -0,0 +1,24 @@ +** README ** + +[Aim] +User can use certctl to fetch existing certificate, create certificate. It will +also show the corresponding input needed for ipsec preconfiguration. + + +[Build] +go build -o certctl ./certctl.go + + +[Usage] +Usage of ./certctl: + -certName string + Certificate name to query + -ip string + SDEWAN Central Controller IP Address (default "10.233.117.240") + -overlay string + Overlay the cert belongs to + -port string + SDEWAN Central Controller Port Number (default "9015") + +Command: +./certctl --ip --port --overlay --certName diff --git a/central-controller/src/scc/tools/certctl/certctl.go b/central-controller/src/scc/tools/certctl/certctl.go new file mode 100644 index 0000000..84bb183 --- /dev/null +++ b/central-controller/src/scc/tools/certctl/certctl.go @@ -0,0 +1,149 @@ +package main + +import ( + "io/ioutil" + "flag" + "encoding/base64" + "encoding/json" + "log" + "bytes" + "net/http" + "errors" + "os" + "strings" + "fmt" +) + +const ( + overlayCollection="overlays" + certificateCollection="certificates" +) + +type CertData struct { + RootCA string + Ca string + Key string +} + +func main(){ + servIp := flag.String("ip", "10.233.117.240", "SDEWAN Central Controller IP Address") + servPort := flag.String("port", "9015", "SDEWAN Central Controller Port Number") + overlayName := flag.String("overlay", "", "Overlay the cert belongs to") + certName := flag.String("certName", "", "Certificate name to query") + flag.Parse() + + overlayUrl := "http://" + *servIp + ":" + *servPort + "/scc/v1/" + overlayCollection + certUrl := overlayUrl + "/" + *overlayName + "/" + certificateCollection + certObj := `{"metadata":{"name":"` + *certName + `","description":"object 1","userData1":"","userData2":""},"spec":{},"data":{"rootca":"","ca":"","key":""}}` + + _, _, err := getObject(overlayUrl, *overlayName) + if err != nil { + log.Println("Fetch overlay", *overlayName,"with error", err) + log.Println("Please re-create the overlay") + os.Exit(0) + } + + log.Println("Fetch certificate with name", *certName, "within overlay", *overlayName) + res, resp_code, err := getObject(certUrl, *certName) + if err != nil { + if resp_code != 500 { + log.Println("Fetch certificate with name", *certName, "with error", err) + os.Exit(0) + } + + log.Println("Certificate not found. Creating certificate with name", *certName) + res, err = createObject(certUrl, certObj) + if err != nil { + log.Println("Certificate creation failed with error", err) + os.Exit(0) + } + parseCertBundle(res) + os.Exit(0) + } + parseCertBundle(res) + +} + +func callRest(method string, url string, request string) (string, int, error) { + client := &http.Client{} + req_body := bytes.NewBuffer([]byte(request)) + req, _ := http.NewRequest(method, url, req_body) + + req.Header.Set("Cache-Control", "no-cache") + + resp, err := client.Do(req) + if err != nil { + return "", 0, err + } + defer resp.Body.Close() + + body, _ := ioutil.ReadAll(resp.Body) + if resp.StatusCode >= 400 { + return "", resp.StatusCode, errors.New(string(body)) + } + + return string(body), resp.StatusCode, nil +} + +func createObject(baseUrl string, obj_str string) (string, error) { + url := baseUrl + + res, _, err := callRest("POST", url, obj_str) + if err != nil { + return "", err + } + + return res, nil +} + +func getObject(baseUrl string, name string) (string, int, error) { + url := baseUrl + "/" + name + + res, resp_code, err := callRest("GET", url, "") + if err != nil { + return "", resp_code, err + } + + return res, resp_code, nil +} + +func parseCertBundle(val string) (string, string, string, error) { + var vi interface{} + err := json.Unmarshal([]byte(val), &vi) + if err != nil { + log.Println("Error in formatting cert data", err) + return "", "", "", err + } + + data_interface := vi.(map[string]interface{})["data"] + data, err := json.Marshal(data_interface) + if err != nil { + log.Println("Error in formatting cert data", err) + return "", "", "", err + } + + var certData CertData + err = json.Unmarshal(data, &certData) + if err != nil { + log.Println("Error in formatting cert data", err) + return "", "", "", err + } + + ca_decoded, err := base64.StdEncoding.DecodeString(certData.RootCA) + if err != nil { + log.Println("Error in formatting cert rootca data", err) + return "", "", "", err + } + + caChain := strings.SplitAfter(string(ca_decoded), "-----END CERTIFICATE-----") + + ca_encoded := base64.StdEncoding.EncodeToString([]byte(caChain[1])) + fmt.Println("Input for shared_ca: ") + fmt.Println(ca_encoded) + fmt.Println("Input for local_public_cert: ") + fmt.Println(certData.Ca) + fmt.Println("Input for local_private_cert: ") + fmt.Println(certData.Key) + + return certData.Ca, certData.Key, ca_encoded, nil +} diff --git a/central-controller/src/scc/tools/certctl/go.mod b/central-controller/src/scc/tools/certctl/go.mod new file mode 100644 index 0000000..fb3ebd8 --- /dev/null +++ b/central-controller/src/scc/tools/certctl/go.mod @@ -0,0 +1,3 @@ +module scc/tools/certctl + +go 1.17 -- 2.16.6