zerosslIPCert

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 10, 2023 License: Apache-2.0 Imports: 17 Imported by: 0

README

zerossl-ip-cert · License Go Report Card Go Reference Build workflow

⚠️WARNING: ZeroSSL removed the Delete Certificate API endpoint, free account can't renew certificate infinitely.

zerossl-ip-cert is a automation tool for issuing ZeroSSL IP certificates.

  • Use ZeroSSL REST API to implement certificate issuing.
  • Mainly made for IP certificates (ipv4 only for now).
  • Call external program for automatically verification.
  • Painless certificate renewal.
  • Cross platform (Linux/Macos/Windows).

Installation

  • Package zerossl-ip-cert contains ZeroSSL REST API client, one can just go get github.com/tinkernels/zerossl-ip-cert and import it to use the client.
  • To build static executables, clone this repository and make release , or you can make your desire target binary, just take a look at the Makefile.

Usage

zerossl-ip-cert rely on configuration file to run. To archive the goal of issuing certificate automatically, you need do some additional work, saying the external hook.

Usage Info
Usage: zerossl-ip-cert [ -renew ] -config CONFIG_FILE

  -config string
        Config file
  -renew
        Renew existing certs only
Configuration File

You can find a sample configuration file here, with enough comments in it.

And also a sample state record file here, just for troubleshooting.

External Hook

zerossl-ip-cert use HTTP_CSR_HASH validation method to verify domains (including ip address surely), get more information from the ZeroSSL official documentation.

So you should have a http server running and prepare hook programs to finish the domain verification.

  • verify-hook will be called before domain verification, some environment variables will be passed to it.

    ZEROSSL_HTTP_FV_HOST stands for listening host, here will be ip address.

    ZEROSSL_HTTP_FV_PATH stands for url path, where verification content will locate.

    ZEROSSL_HTTP_FV_PORT stands for listening port, ZeroSSL only reach port 80 of your http server according to use experience.

    ZEROSSL_HTTP_FV_CONTENT stands for validation content, ZeroSSL will check it when domain verification started.

    And a sample script for nginx can be found here, a sample script for caddy can be found here.

    P.S. When running in Windows OS, text lines are concatenated with spaces in %ZEROSSL_HTTP_FV_CONTENT%, as windows doesn't accept multiline variables without using magic.

  • post-hook will be called after certification downloading, and some other environment variables will be passed to it.

    ZEROSSL_CERT_FPATH stands for the store path of certificate.

    ZEROSSL_KEY_FPATH stands for the store path of private key.

    And a sample script for nginx can be found here, a sample script for caddy can be found here.

License

Apache-2.0

Documentation

Index

Constants

View Source
const ApiEndpoint = "api.zerossl.com"

ApiEndpoint is the zerossl api endpoint.

Variables

View Source
var ApiReqFactory = struct {
	// Request of creating a new certificate.
	CreateCertificate func(accessKey, certificateDomains, certificateCsr, certificateValidityDays,
		strictDomains string) (req *http.Request)
	// Request of listing all certificates.
	ListCertificates func(accessKey, certificateStatus, search, limit, page string) (req *http.Request)
	// Request of getting a certificate.
	GetCertificate func(accessKey, id string) (req *http.Request)
	// Request of verifying a certificate.
	VerifyDomains func(accessKey, certificateId, validationMethod, validationEmail string) (req *http.Request)
	// Request of verification status.
	VerificationStatus func(accessKey, id string) (req *http.Request)
	// Request of cancelation a certificate.
	CancelCertificate func(accessKey, id string) (req *http.Request)
	// Request of downloading a certificate.
	DownloadCertificateInline func(accessKey, certID, includeCrossSigned string) (req *http.Request)
}{
	CreateCertificate: func(accessKey, certificateDomains, certificateCsr, certificateValidityDays,
		strictDomains string) (req *http.Request) {
		req = &http.Request{Method: http.MethodPost}
		url_ := &url.URL{Scheme: "https", Host: ApiEndpoint, Path: "/certificates"}
		q_ := make(url.Values)
		q_.Add("access_key", accessKey)
		url_.RawQuery = q_.Encode()
		req.URL = url_
		bodyForm_ := make(url.Values)
		if certificateDomains != "" {
			bodyForm_.Add("certificate_domains", certificateDomains)
		}
		if certificateCsr != "" {
			bodyForm_.Add("certificate_csr", certificateCsr)
		}
		if certificateValidityDays != "" {
			bodyForm_.Add("certificate_validity_days", certificateValidityDays)
		}
		if strictDomains != "" {
			bodyForm_.Add("strict_domains", strictDomains)
		}
		if len(bodyForm_) > 0 {
			req.Header = make(http.Header)
			req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
			req.Body = io.NopCloser(strings.NewReader(bodyForm_.Encode()))
		}
		return
	},
	ListCertificates: func(accessKey, certificateStatus, search, limit, page string) (req *http.Request) {
		req = &http.Request{Method: http.MethodGet}
		url_ := &url.URL{Scheme: "https", Host: ApiEndpoint, Path: "/certificates"}
		q_ := make(url.Values)
		q_.Add("access_key", accessKey)
		if certificateStatus != "" {
			q_.Add("certificate_status", certificateStatus)
		}
		if search != "" {
			q_.Add("search", search)
		}
		if limit != "" {
			q_.Add("limit", limit)
		}
		if page != "" {
			q_.Add("page", page)
		}
		url_.RawQuery = q_.Encode()
		req.URL = url_
		return
	},
	GetCertificate: func(accessKey, id string) (req *http.Request) {
		req = &http.Request{Method: http.MethodGet}
		url_ := &url.URL{Scheme: "https", Host: ApiEndpoint, Path: "/certificates/" + id}
		q_ := make(url.Values)
		q_.Add("access_key", accessKey)
		url_.RawQuery = q_.Encode()
		req.URL = url_
		return
	},
	VerifyDomains: func(accessKey, certificateId, validationMethod, validationEmail string) (req *http.Request) {
		req = &http.Request{Method: http.MethodPost}
		url_ := &url.URL{Scheme: "https", Host: ApiEndpoint, Path: "/certificates/" + certificateId + "/challenges"}
		q_ := make(url.Values)
		q_.Add("access_key", accessKey)
		url_.RawQuery = q_.Encode()
		req.URL = url_
		bodyForm_ := make(url.Values)
		if validationMethod != "" {
			bodyForm_.Add("validation_method", validationMethod)
		}
		if validationEmail != "" {
			bodyForm_.Add("validation_email", validationEmail)
		}
		if len(bodyForm_) > 0 {
			req.Header = make(http.Header)
			req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
			req.Body = io.NopCloser(strings.NewReader(bodyForm_.Encode()))
		}
		return
	},
	VerificationStatus: func(accessKey, id string) (req *http.Request) {
		req = &http.Request{Method: http.MethodGet}
		url_ := &url.URL{Scheme: "https", Host: ApiEndpoint, Path: "/certificates/" + id + "/status"}
		q_ := make(url.Values)
		q_.Add("access_key", accessKey)
		url_.RawQuery = q_.Encode()
		req.URL = url_
		return
	},
	CancelCertificate: func(accessKey, id string) (req *http.Request) {
		req = &http.Request{Method: http.MethodPost}
		url_ := &url.URL{Scheme: "https", Host: ApiEndpoint, Path: "/certificates/" + id + "/cancel"}
		q_ := make(url.Values)
		q_.Add("access_key", accessKey)
		url_.RawQuery = q_.Encode()
		req.URL = url_
		return
	},
	DownloadCertificateInline: func(accessKey, certID, includeCrossSigned string) (req *http.Request) {
		req = &http.Request{Method: http.MethodGet}
		url_ := &url.URL{Scheme: "https", Host: ApiEndpoint, Path: "/certificates/" + certID + "/download/return"}
		q_ := make(url.Values)
		q_.Add("access_key", accessKey)
		if includeCrossSigned != "" {
			q_.Add("include_cross_signed", includeCrossSigned)
		}
		url_.RawQuery = q_.Encode()
		req.URL = url_
		return
	},
}

ApiReqFactory is a factory for creating API requests.

View Source
var CertStatus = struct {
	Draft             string
	PendingValidation string
	Issued            string
	Cancelled         string
	ExpiringSoon      string
	Expired           string
}{
	Draft:             "draft",
	PendingValidation: "pending_validation",
	Issued:            "issued",
	Cancelled:         "cancelled",
	ExpiringSoon:      "expiring_soon",
	Expired:           "expired",
}

CertStatus represents the status of a certificate.

View Source
var EcdsaCurves = map[string]elliptic.Curve{
	"P-256": elliptic.P256(),
	"P-384": elliptic.P384(),
}
View Source
var SignatureAlgorithms = map[string]x509.SignatureAlgorithm{
	"SHA256-RSA":   x509.SHA256WithRSA,
	"SHA384-RSA":   x509.SHA384WithRSA,
	"ECDSA-SHA256": x509.ECDSAWithSHA256,
	"ECDSA-SHA384": x509.ECDSAWithSHA384,
}
View Source
var VerifyDomainsMethod = struct {
	Email        string // EMAIL
	CNameCsrHash string //CNAME_CSR_HASH
	HttpCsrHash  string //HTTP_CSR_HASH
	HttpsCsrHash string //HTTPS_CSR_HASH
}{
	Email:        "EMAIL",
	CNameCsrHash: "CNAME_CSR_HASH",
	HttpCsrHash:  "HTTP_CSR_HASH",
	HttpsCsrHash: "HTTPS_CSR_HASH",
}

VerifyDomainsMethod represents the method of verifying domains.

Functions

func CSRGeneratorWrapper

func CSRGeneratorWrapper(keyType string, subj pkix.Name, key interface{}, sigAlgStr string) (csr []byte, err error)

CSRGeneratorWrapper is a wrapper for generating CSR.

func GenEccCSR

func GenEccCSR(subj pkix.Name, key *ecdsa.PrivateKey, sigAlg x509.SignatureAlgorithm) (csr []byte, err error)

GenEccCSR generates a new ECC CSR.

func GenEccKey

func GenEccKey(curve elliptic.Curve) (key *ecdsa.PrivateKey)

GenEccKey generates a new ECC private key.

func GenRsaCSR

func GenRsaCSR(subj pkix.Name, key *rsa.PrivateKey, sigAlg x509.SignatureAlgorithm) (csr []byte, err error)

GenRsaCSR generates a new RSA CSR.

func GenRsaKey

func GenRsaKey(bits int) *rsa.PrivateKey

GenRsaKey generates a new RSA private key.

func GetCSRString

func GetCSRString(csr []byte) (csrStr string)

GetCSRString returns a CSR as a string.

func KeyGeneratorWrapper

func KeyGeneratorWrapper(keyType string, keyBits int, keyCurve string) (key interface{})

KeyGeneratorWrapper is a wrapper for generating keys.

func WriteCSRPem

func WriteCSRPem(out io.Writer, csr []byte) (err error)

WriteCSRPem writes a CSR to a PEM file.

func WriteEccPrivKeyPem

func WriteEccPrivKeyPem(out io.Writer, key *ecdsa.PrivateKey) (err error)

WriteEccPrivKeyPem writes an ECC private key to a PEM file.

func WritePrivKeyWrapper

func WritePrivKeyWrapper(keyType string, key interface{}, keyFile string) (err error)

WritePrivKeyWrapper is a wrapper for writing private keys.

func WriteRsaPrivKeyPem

func WriteRsaPrivKeyPem(out io.Writer, key *rsa.PrivateKey) (err error)

WriteRsaPrivKeyPem writes an RSA private key to a PEM file.

Types

type CertificateContentModel

type CertificateContentModel struct {
	Certificate string `json:"certificate.crt"`
	CaBundle    string `json:"ca_bundle.crt"`
}

type CertificateInfoModel

type CertificateInfoModel struct {
	ID                string              `json:"id"`
	Type              string              `json:"type"`
	CommonName        string              `json:"common_name"`
	AdditionalDomains string              `json:"additional_domains"`
	Created           string              `json:"created"`
	Expires           string              `json:"expires"`
	Status            string              `json:"status"`
	ValidationType    string              `json:"validation_type"`
	ValidationEmails  string              `json:"validation_email"`
	ReplacementFor    string              `json:"replacement_for"`
	Validation        ValidationInfoModel `json:"validation,omitempty"`
}

type Client

type Client struct {
	ApiKey string // API key
}

Client is a client for ZeroSSL. Refer: https://zerossl.com/documentation/api

func (*Client) CancelCert added in v1.0.1

func (c *Client) CancelCert(id string) (err error)

Cancel a certificate.

func (*Client) CleanUnfinished added in v0.5.1

func (c *Client) CleanUnfinished() (err error)

func (*Client) CreateCert

func (c *Client) CreateCert(domains, csr, days, isStrictDomains string) (cert CertificateInfoModel, err error)

CreateCert creates a certificate with the given parameters.

func (*Client) DownloadCertInline

func (c *Client) DownloadCertInline(certID, includeCrossSigned string) (cert CertificateContentModel, err error)

DownloadCertInline returns the certificate in PEM format.

func (*Client) GetCert

func (c *Client) GetCert(id string) (cert CertificateInfoModel, err error)

GetCert returns a certificate.

func (*Client) ListCerts

func (c *Client) ListCerts(status, search, limit, page string) (listCertsRsp ListCertsModel, err error)

ListCerts returns a list of certificates with optional filters.

func (*Client) VerificationStatus

func (c *Client) VerificationStatus(certID string) (verificationStatusRsp VerificationStatusModel, err error)

VerificationStatus returns the verification status of a certificate.

func (*Client) VerifyDomains

func (c *Client) VerifyDomains(certID, validationMethod, validationEmail string) (verifyDomainsRsp VerifyDomainsModel, err error)

VerifyDomains verifies domains of specified certificate with given validation info.

type ListCertsModel

type ListCertsModel struct {
	TotalCount  int `json:"total_count"`
	ResultCount int `json:"result_count"`
	// Don't use the page field, because page in response is dynamic typed.
	//Page        string                 `json:"page"`
	Limit   int                    `json:"limit"`
	Results []CertificateInfoModel `json:"results,omitempty"`
}

type OtherValidationInfoModel

type OtherValidationInfoModel struct {
	FileValidationUrlHttp  string   `json:"file_validation_url_http"`
	FileValidationUrlHttps string   `json:"file_validation_url_https"`
	FileValidationContent  []string `json:"file_validation_content"`
	CNameValidationP1      string   `json:"cname_validation_p1"`
	CNameValidationP2      string   `json:"cname_validation_p2"`
}

type ValidationDetailModel

type ValidationDetailModel struct {
	Method string `json:"method"`
	Status string `json:"status"`
}

type ValidationInfoModel

type ValidationInfoModel struct {
	EmailValidation map[string][]string                 `json:"email_validation"`
	OtherMethods    map[string]OtherValidationInfoModel `json:"other_methods"`
}

type VerificationStatusModel

type VerificationStatusModel struct {
	ValidationCompleted int                              `json:"validation_completed"`
	Details             map[string]ValidationDetailModel `json:"details"`
}

type VerifyDomainsErrorDetailModel

type VerifyDomainsErrorDetailModel struct {
	CNameFound    int    `json:"cname_found"`
	RecordCorrect int    `json:"record_correct"`
	TargetHost    string `json:"target_host"`
	TargetRecord  string `json:"target_record"`
	ActualRecord  string `json:"actual_record"`
}

type VerifyDomainsErrorModel

type VerifyDomainsErrorModel struct {
	Code    int                           `json:"code"`
	Type    string                        `json:"type"`
	Details VerifyDomainsErrorDetailModel `json:"details"`
}

type VerifyDomainsModel

type VerifyDomainsModel struct {
	Success bool                    `json:"success"`
	Error   VerifyDomainsErrorModel `json:"error"`
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL