diff --git a/system_certificate_local.go b/system_certificate_local.go new file mode 100644 index 0000000..0b8d0d2 --- /dev/null +++ b/system_certificate_local.go @@ -0,0 +1,194 @@ +package gofortiadc + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "mime/multipart" +) + +// SystemLocalCertificate represents a real server request/response +type SystemLocalCertificate struct { + CaType string `json:"ca_type"` + Comments string `json:"comments"` + Extension []interface{} `json:"extension"` + Fingerprint string `json:"fingerprint"` + Hash string `json:"hash"` + Issuer string `json:"issuer"` + Mkey string `json:"mkey"` + PinSha256 string `json:"pin-sha256"` + Sn string `json:"sn"` + Status string `json:"status"` + Subject string `json:"subject"` + Type string `json:"type"` + Validfrom string `json:"validfrom"` + Validto string `json:"validto"` + Version int `json:"version"` +} + +// SystemGetLocalCertificates returns the list of all local certificates +func (c *Client) SystemGetLocalCertificates() ([]SystemLocalCertificate, error) { + req, err := c.NewRequest("GET", fmt.Sprintf("%s/api/system_certificate_local", c.Address), nil) + if err != nil { + return []SystemLocalCertificate{}, err + } + + res, err := c.Client.Do(req) + if err != nil { + return []SystemLocalCertificate{}, err + } + defer res.Body.Close() + + if res.StatusCode != 200 { + return []SystemLocalCertificate{}, fmt.Errorf("failed to get local certificates list with status code: %d", res.StatusCode) + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return []SystemLocalCertificate{}, err + } + + var SystemLocalCertificatePayload struct { + Payload []SystemLocalCertificate + } + err = json.Unmarshal(body, &SystemLocalCertificatePayload) + if err != nil { + return []SystemLocalCertificate{}, err + } + + return SystemLocalCertificatePayload.Payload, nil +} + +// SystemGetLocalCertificate returns a real server by name +func (c *Client) SystemGetLocalCertificate(name string) (SystemLocalCertificate, error) { + + certificates, err := c.SystemGetLocalCertificates() + if err != nil { + return SystemLocalCertificate{}, err + } + + for _, certificate := range certificates { + if certificate.Mkey == name { + return certificate, nil + } + } + + return SystemLocalCertificate{}, fmt.Errorf("local certificate %s not found", name) +} + +// SystemCreateLocalCertificate creates a new local certificate +func (c *Client) SystemCreateLocalCertificate(name, password string, cert, key []byte) error { + + form, contentType, err := createCertificateForm(name, password, cert, key) + if err != nil { + return err + } + + req, err := c.NewRequest("POST", fmt.Sprintf("%s/api/upload/certificate_local", c.Address), form) + if err != nil { + return err + } + + req.Header.Set("Content-Type", contentType) + + res, err := c.Client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + if res.StatusCode != 200 { + return fmt.Errorf("local certificate creation failed with status code: %d", res.StatusCode) + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return err + } + + resJSON := struct{ Payload int }{} + err = json.Unmarshal(body, &resJSON) + if err != nil { + return err + } + + if resJSON.Payload != 0 { + return fmt.Errorf("local certificate creation failed: %s ", getErrorMessage(resJSON.Payload)) + } + + return nil +} + +func createCertificateForm(name, password string, cert, key []byte) (form *bytes.Buffer, contentType string, err error) { + + var b bytes.Buffer + + w := multipart.NewWriter(&b) + defer w.Close() + + w.WriteField("mkey", name) + w.WriteField("vdom", "global") + w.WriteField("type", "CertKey") + w.WriteField("passwd", password) + + certPart, err := w.CreateFormFile("cert", "tls.crt") + if err != nil { + return &b, contentType, err + } + + _, err = certPart.Write(cert) + if err != nil { + return &b, contentType, err + } + + keyPart, err := w.CreateFormFile("key", "tls.key") + if err != nil { + return &b, contentType, err + } + + _, err = keyPart.Write(key) + + return &b, w.FormDataContentType(), err +} + +// SystemDeleteLocalCertificate deletes an existing local certificate +func (c *Client) SystemDeleteLocalCertificate(name string) error { + + if len(name) == 0 { + return errors.New("local certificate name cannot be empty") + } + + req, err := c.NewRequest("DELETE", fmt.Sprintf("%s/api/system_certificate_local?mkey=%s", c.Address, name), nil) + if err != nil { + return err + } + + res, err := c.Client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + if res.StatusCode != 200 { + return fmt.Errorf("local certificate deletion failed with status code: %d", res.StatusCode) + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return err + } + + resJSON := struct{ Payload int }{} + err = json.Unmarshal(body, &resJSON) + if err != nil { + return err + } + + if resJSON.Payload != 0 { + return fmt.Errorf("local certificate deletion failed: %s", getErrorMessage(resJSON.Payload)) + } + + return nil +} diff --git a/system_certificate_local_group.go b/system_certificate_local_group.go new file mode 100644 index 0000000..2e88c80 --- /dev/null +++ b/system_certificate_local_group.go @@ -0,0 +1,145 @@ +package gofortiadc + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" +) + +// SystemLocalCertificateGroup represents a local certificate request/response +type SystemLocalCertificateGroup struct { + Mkey string `json:"mkey"` +} + +// SystemGetLocalCertificateGroups returns the list of all local certificate groups +func (c *Client) SystemGetLocalCertificateGroups() ([]SystemLocalCertificateGroup, error) { + req, err := c.NewRequest("GET", fmt.Sprintf("%s/api/system_certificate_local_cert_group", c.Address), nil) + if err != nil { + return []SystemLocalCertificateGroup{}, err + } + + res, err := c.Client.Do(req) + if err != nil { + return []SystemLocalCertificateGroup{}, err + } + defer res.Body.Close() + + if res.StatusCode != 200 { + return []SystemLocalCertificateGroup{}, fmt.Errorf("failed to get local certificate groups list with status code: %d", res.StatusCode) + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return []SystemLocalCertificateGroup{}, err + } + + var SystemLocalCertificateGroupsPayload struct { + Payload []SystemLocalCertificateGroup + } + err = json.Unmarshal(body, &SystemLocalCertificateGroupsPayload) + if err != nil { + return []SystemLocalCertificateGroup{}, err + } + + return SystemLocalCertificateGroupsPayload.Payload, nil +} + +// SystemGetLocalCertificateGroup returns a local certificate group by name +func (c *Client) SystemGetLocalCertificateGroup(name string) (SystemLocalCertificateGroup, error) { + + groups, err := c.SystemGetLocalCertificateGroups() + if err != nil { + return SystemLocalCertificateGroup{}, err + } + + for _, group := range groups { + if group.Mkey == name { + return group, nil + } + } + + return SystemLocalCertificateGroup{}, fmt.Errorf("local certificate group %s not found", name) +} + +// SystemCreateLocalCertificateGroup creates a new local certificate group +func (c *Client) SystemCreateLocalCertificateGroup(lcg SystemLocalCertificateGroup) error { + + payloadJSON, err := json.Marshal(lcg) + if err != nil { + return err + } + + req, err := c.NewRequest("POST", fmt.Sprintf("%s/api/system_certificate_local_cert_group", c.Address), bytes.NewReader(payloadJSON)) + if err != nil { + return err + } + + res, err := c.Client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + if res.StatusCode != 200 { + return fmt.Errorf("local certificate group creation failed with status code: %d", res.StatusCode) + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return err + } + + resJSON := struct{ Payload int }{} + err = json.Unmarshal(body, &resJSON) + if err != nil { + return err + } + + if resJSON.Payload != 0 { + return fmt.Errorf("local certificate group creation failed: %s ", getErrorMessage(resJSON.Payload)) + } + + return nil +} + +// SystemDeleteLocalCertificateGroup deletes an existing local certificate group +func (c *Client) SystemDeleteLocalCertificateGroup(name string) error { + + if len(name) == 0 { + return errors.New("local certificate group name cannot be empty") + } + + req, err := c.NewRequest("DELETE", fmt.Sprintf("%s/api/system_certificate_local_cert_group?mkey=%s", c.Address, name), nil) + if err != nil { + return err + } + + res, err := c.Client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + if res.StatusCode != 200 { + return fmt.Errorf("local certificate group deletion failed with status code: %d", res.StatusCode) + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return err + } + + resJSON := struct{ Payload int }{} + err = json.Unmarshal(body, &resJSON) + if err != nil { + return err + } + + if resJSON.Payload != 0 { + return fmt.Errorf("local certificate group deletion failed: %s", getErrorMessage(resJSON.Payload)) + } + + return nil +} diff --git a/system_certificate_local_group_member.go b/system_certificate_local_group_member.go new file mode 100644 index 0000000..8d41d13 --- /dev/null +++ b/system_certificate_local_group_member.go @@ -0,0 +1,195 @@ +package gofortiadc + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" +) + +// SystemLocalCertificateGroup represents a local certificate request/response +type SystemLocalCertificateGroupMember struct { + OCSPStapling string `json:"OCSP_stapling"` + Default string `json:"default"` + ExtraOCSPStapling string `json:"extra_OCSP_stapling"` + ExtraIntermediateCag string `json:"extra_intermediate_cag"` + ExtraLocalCert string `json:"extra_local_cert"` + IntermediateCag string `json:"intermediate_cag"` + LocalCert string `json:"local_cert"` + Mkey string `json:"mkey"` +} + +// SystemGetLocalCertificateGroupMembers returns the list of all local certificate group members +func (c *Client) SystemGetLocalCertificateGroupMembers(group string) ([]SystemLocalCertificateGroupMember, error) { + + req, err := c.NewRequest("GET", fmt.Sprintf("%s/api/system_certificate_local_cert_group_child_group_member?pkey=%s", c.Address, group), nil) + if err != nil { + return []SystemLocalCertificateGroupMember{}, err + } + + res, err := c.Client.Do(req) + if err != nil { + return []SystemLocalCertificateGroupMember{}, err + } + defer res.Body.Close() + + if res.StatusCode != 200 { + return []SystemLocalCertificateGroupMember{}, fmt.Errorf("failed to get local certificate group members list with status code: %d", res.StatusCode) + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return []SystemLocalCertificateGroupMember{}, err + } + + var SystemLocalCertificateGroupMembersPayload struct { + Payload []SystemLocalCertificateGroupMember + } + err = json.Unmarshal(body, &SystemLocalCertificateGroupMembersPayload) + if err != nil { + return []SystemLocalCertificateGroupMember{}, err + } + + return SystemLocalCertificateGroupMembersPayload.Payload, nil +} + +// SystemGetLocalCertificateGroupMember returns a local certificate group member by mkey +func (c *Client) SystemGetLocalCertificateGroupMember(group, mkey string) (SystemLocalCertificateGroupMember, error) { + + members, err := c.SystemGetLocalCertificateGroupMembers(group) + if err != nil { + return SystemLocalCertificateGroupMember{}, err + } + + for _, member := range members { + if member.Mkey == mkey { + return member, nil + } + } + + return SystemLocalCertificateGroupMember{}, fmt.Errorf("local certificate group member %s not found", mkey) +} + +// SystemCreateLocalCertificateGroupMember creates a new local certificate group member +func (c *Client) SystemCreateLocalCertificateGroupMember(group string, lcgm SystemLocalCertificateGroupMember) error { + + payloadJSON, err := json.Marshal(lcgm) + if err != nil { + return err + } + + req, err := c.NewRequest("POST", fmt.Sprintf("%s/api/system_certificate_local_cert_group_child_group_member?pkey=%s", c.Address, group), bytes.NewReader(payloadJSON)) + if err != nil { + return err + } + + res, err := c.Client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + if res.StatusCode != 200 { + return fmt.Errorf("local certificate group member creation failed with status code: %d", res.StatusCode) + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return err + } + + resJSON := struct{ Payload int }{} + err = json.Unmarshal(body, &resJSON) + if err != nil { + return err + } + + if resJSON.Payload != 0 { + return fmt.Errorf("local certificate group member creation failed: %s ", getErrorMessage(resJSON.Payload)) + } + + return nil +} + +// SystemUpdateLocalCertificateGroupMember updates an existing local certificate group member +func (c *Client) SystemUpdateLocalCertificateGroupMember(group, mkey string, lcgm SystemLocalCertificateGroupMember) error { + + payloadJSON, err := json.Marshal(lcgm) + if err != nil { + return err + } + + req, err := c.NewRequest("PUT", fmt.Sprintf("%s/api/system_certificate_local_cert_group_child_group_member?mkey=%s&pkey=%s", c.Address, mkey, group), bytes.NewReader(payloadJSON)) + if err != nil { + return err + } + + res, err := c.Client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + if res.StatusCode != 200 { + return fmt.Errorf("local certificate group member update failed with status code: %d", res.StatusCode) + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return err + } + fmt.Println(string(body)) + + resJSON := struct{ Payload int }{} + err = json.Unmarshal(body, &resJSON) + if err != nil { + return err + } + + if resJSON.Payload != 0 { + return fmt.Errorf("local certificate group member update failed: %s", getErrorMessage(resJSON.Payload)) + } + + return nil +} + +// SystemDeleteLocalCertificateGroupMember deletes an existing local certificate group member +func (c *Client) SystemDeleteLocalCertificateGroupMember(group, mkey string) error { + + if len(group) == 0 { + return errors.New("local certificate group name cannot be empty") + } + + req, err := c.NewRequest("DELETE", fmt.Sprintf("%s/api/system_certificate_local_cert_group_child_group_member?mkey=%s&pkey=%s", c.Address, mkey, group), nil) + if err != nil { + return err + } + + res, err := c.Client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + if res.StatusCode != 200 { + return fmt.Errorf("local certificate group member deletion failed with status code: %d", res.StatusCode) + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return err + } + + resJSON := struct{ Payload int }{} + err = json.Unmarshal(body, &resJSON) + if err != nil { + return err + } + + if resJSON.Payload != 0 { + return fmt.Errorf("local certificate group member deletion failed: %s", getErrorMessage(resJSON.Payload)) + } + + return nil +} diff --git a/system_certificate_local_group_member_test.go b/system_certificate_local_group_member_test.go new file mode 100644 index 0000000..6dee152 --- /dev/null +++ b/system_certificate_local_group_member_test.go @@ -0,0 +1,97 @@ +package gofortiadc + +import ( + "os" + "testing" +) + +func TestClient_SystemGetLocalCertificateGroupMembers(t *testing.T) { + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + res, err := client.SystemGetLocalCertificateGroupMembers("goforti_group") + if err != nil { + t.Logf("%+v", res) + t.Fatal(err) + } +} + +func TestClient_SystemGetLocalCertificateGroupMember(t *testing.T) { + if os.Getenv("TEST_LENS") != "true" { + t.Skip() + } + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + res, err := client.SystemGetLocalCertificateGroupMember("goforti_group", "1") + if err != nil { + t.Logf("%+v", res) + t.Fatal(err) + } +} + +func TestClient_SystemCreateLocalCertificateGroupMember(t *testing.T) { + if os.Getenv("TEST_LENS") != "true" { + t.Skip() + } + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + member := SystemLocalCertificateGroupMember{ + Default: "disable", + LocalCert: "gofortiadc", + } + + err = client.SystemCreateLocalCertificateGroupMember("goforti_group", member) + if err != nil { + t.Fatal(err) + } +} + +func TestClient_SystemUpdateLocalCertificateGroupMember(t *testing.T) { + if os.Getenv("TEST_LENS") != "true" { + t.Skip() + } + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + member := SystemLocalCertificateGroupMember{ + Default: "enable", + IntermediateCag: "Letsencrypt", + LocalCert: "gofortiadc", + Mkey: "1", + } + + err = client.SystemUpdateLocalCertificateGroupMember("goforti_group", "1", member) + if err != nil { + t.Fatal(err) + } +} + +func TestClient_SystemDeleteLocalCertificateGroupMember(t *testing.T) { + if os.Getenv("TEST_LENS") != "true" { + t.Skip() + } + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + err = client.SystemDeleteLocalCertificateGroupMember("goforti_group", "1") + if err != nil { + t.Fatal(err) + } +} diff --git a/system_certificate_local_group_test.go b/system_certificate_local_group_test.go new file mode 100644 index 0000000..0cb57d0 --- /dev/null +++ b/system_certificate_local_group_test.go @@ -0,0 +1,72 @@ +package gofortiadc + +import ( + "os" + "testing" +) + +func TestClient_SystemGetLocalCertificateGroups(t *testing.T) { + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + res, err := client.SystemGetLocalCertificateGroups() + if err != nil { + t.Logf("%+v", res) + t.Fatal(err) + } +} + +func TestClient_SystemGetLocalCertificateGroup(t *testing.T) { + if os.Getenv("TEST_LENS") != "true" { + t.Skip() + } + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + _, err = client.SystemGetLocalCertificateGroup("goforti_group") + if err != nil { + t.Fatal(err) + } +} + +func TestClient_SystemCreateLocalCertificateGroup(t *testing.T) { + if os.Getenv("TEST_LENS") != "true" { + t.Skip() + } + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + group := SystemLocalCertificateGroup{ + Mkey: "goforti_group", + } + + err = client.SystemCreateLocalCertificateGroup(group) + if err != nil { + t.Fatal(err) + } +} + +func TestClient_SystemDeleteLocalCertificateGroup(t *testing.T) { + if os.Getenv("TEST_LENS") != "true" { + t.Skip() + } + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + err = client.SystemDeleteLocalCertificateGroup("goforti_group") + if err != nil { + t.Fatal(err) + } +} diff --git a/system_certificate_local_test.go b/system_certificate_local_test.go new file mode 100644 index 0000000..de13b4d --- /dev/null +++ b/system_certificate_local_test.go @@ -0,0 +1,111 @@ +package gofortiadc + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "os" + "testing" + "time" +) + +func TestClient_SystemGetLocalCertificates(t *testing.T) { + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + res, err := client.SystemGetLocalCertificates() + if err == nil { + t.Logf("%+v", res) + t.Fatal(err) + } +} + +func TestClient_SystemGetLocalCertificate(t *testing.T) { + if os.Getenv("TEST_LENS") != "true" { + t.Skip() + } + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + _, err = client.SystemGetLocalCertificate("Factory") + if err != nil { + t.Fatal(err) + } +} + +func TestClient_SystemCreateLocalCertificate(t *testing.T) { + if os.Getenv("TEST_LENS") != "true" { + t.Skip() + } + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + cert, key, err := generateCertificate() + if err != nil { + t.Fatal(err) + } + + err = client.SystemCreateLocalCertificate("gofortiadc", "", cert, key) + if err != nil { + t.Fatal(err) + } +} + +func TestClient_SystemDeleteLocalCertificate(t *testing.T) { + if os.Getenv("TEST_LENS") != "true" { + t.Skip() + } + + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + err = client.SystemDeleteLocalCertificate("gofortiadc") + if err != nil { + t.Fatal(err) + } +} + +func generateCertificate() (cert, key []byte, err error) { + + rawKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return cert, key, err + } + + template := x509.Certificate{ + Subject: pkix.Name{ + Organization: []string{"Gofortiadc Test"}, + }, + SerialNumber: big.NewInt(1), + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Minute * 30), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + DNSNames: []string{"gofortiadc.test.tld"}, + } + + rawCert, err := x509.CreateCertificate(rand.Reader, &template, &template, &rawKey.PublicKey, rawKey) + if err != nil { + return cert, key, err + } + + cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rawCert}) + key = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(rawKey)}) + + return cert, key, nil +} diff --git a/system_certificate_test.go b/system_certificate_test.go new file mode 100644 index 0000000..31d922f --- /dev/null +++ b/system_certificate_test.go @@ -0,0 +1,75 @@ +package gofortiadc + +import ( + "testing" +) + +func TestSystemCertficate(t *testing.T) { + client, err := NewClientHelper() + if err != nil { + t.Fatal(err) + } + + // Create local certificate + cert, key, err := generateCertificate() + if err != nil { + t.Fatal(err) + } + + err = client.SystemCreateLocalCertificate("gofortiadc", "", cert, key) + if err != nil { + t.Fatalf("SystemCreateLocalCertificate failed with error: %s", err) + } + + // Create local certificate group + group := SystemLocalCertificateGroup{ + Mkey: "goforti_group", + } + + err = client.SystemCreateLocalCertificateGroup(group) + if err != nil { + t.Fatalf("SystemCreateLocalCertificateGroup failed with error: %s", err) + } + + // Create local certificate group member + member := SystemLocalCertificateGroupMember{ + Default: "disable", + LocalCert: "gofortiadc", + } + + err = client.SystemCreateLocalCertificateGroupMember("goforti_group", member) + if err != nil { + t.Fatalf("SystemCreateLocalCertificateGroupMember failed with error: %s", err) + } + + // Update local certificate group member + member = SystemLocalCertificateGroupMember{ + Default: "enable", + IntermediateCag: "Letsencrypt", + LocalCert: "gofortiadc", + Mkey: "1", + } + + err = client.SystemUpdateLocalCertificateGroupMember("goforti_group", "1", member) + if err != nil { + t.Fatalf("SystemUpdateLocalCertificateGroupMember failed with error: %s", err) + } + + // Delete local certificate group member + err = client.SystemDeleteLocalCertificateGroupMember("goforti_group", "1") + if err != nil { + t.Fatalf("SystemDeleteLocalCertificateGroupMember failed with error: %s", err) + } + + // Delete local certificate group + err = client.SystemDeleteLocalCertificateGroup("goforti_group") + if err != nil { + t.Fatalf("SystemDeleteLocalCertificateGroup failed with error: %s", err) + } + + // Delete local certificate + err = client.SystemDeleteLocalCertificate("gofortiadc") + if err != nil { + t.Fatalf("SystemDeleteLocalCertificate failed with error: %s", err) + } +}