Skip to content

Commit cd63b32

Browse files
committed
Add support for ZeroSSL account registration
This commit extends lego library and cli tool to support issuing certificates from ZeroSSL without having to manually create an account. Without this commit ZeroSSL can be used but users need to manually create ZeroSSL account and start `lego` in EAB (External Account Binding) mode. From the `lego` cli tool perspective this commit: Detects if `lego` ir running with ZeroSSL ACME directory `--server https://acme.zerossl.com/v2/DV90` and uses ZeroSSL API to issue keys for EAB. There is no need to provide `--eab`, `--kid`, `--hmac` values anymore. From the library perspective this commit: Creates new method `RegisterWithZeroSSL()` in the `registration` package which takes care of creating ZeroSSL account with a given email. Internally it re-uses `RegisterWithExternalAccountBinding()` method after KID and HMAC are retrieved from ZeroSSL registration endpoint.
1 parent a6ddcac commit cd63b32

File tree

4 files changed

+52
-1
lines changed

4 files changed

+52
-1
lines changed

cmd/cmd_run.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@ func register(ctx *cli.Context, client *lego.Client) (*registration.Resource, er
157157
log.Fatal("You did not accept the TOS. Unable to proceed.")
158158
}
159159

160+
if ctx.String("server") == lego.ZeroSSLDirectory {
161+
return client.Registration.RegisterWithZeroSSL(registration.RegisterOptions{TermsOfServiceAgreed: true})
162+
}
163+
160164
if ctx.Bool("eab") {
161165
kid := ctx.String("kid")
162166
hmacEncoded := ctx.String("hmac")

cmd/setup.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func newClient(ctx *cli.Context, acc registration.User, keyType certcrypto.KeyTy
5252
log.Fatalf("Could not create client: %v", err)
5353
}
5454

55-
if client.GetExternalAccountRequired() && !ctx.IsSet("eab") {
55+
if client.GetExternalAccountRequired() && !ctx.IsSet("eab") && config.CADirURL != lego.ZeroSSLDirectory {
5656
log.Fatal("Server requires External Account Binding. Use --eab with --kid and --hmac.")
5757
}
5858

lego/client_config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ const (
3838

3939
// LEDirectoryStaging URL to the Let's Encrypt staging.
4040
LEDirectoryStaging = "https://acme-staging-v02.api.letsencrypt.org/directory"
41+
42+
// ZeroSSLDirectory URL to the ZeroSSL production.
43+
ZeroSSLDirectory = "https://acme.zerossl.com/v2/DV90"
4144
)
4245

4346
type Config struct {

registration/registar.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package registration
22

33
import (
4+
"encoding/json"
45
"errors"
6+
"fmt"
57
"net/http"
8+
"net/url"
69

710
"github.com/go-acme/lego/v4/acme"
811
"github.com/go-acme/lego/v4/acme/api"
@@ -67,6 +70,47 @@ func (r *Registrar) Register(options RegisterOptions) (*Resource, error) {
6770
return &Resource{URI: account.Location, Body: account.Account}, nil
6871
}
6972

73+
func createZeroSSLAccount(email string) (string, string, error) {
74+
newAccountURL := "http://api.zerossl.com/acme/eab-credentials-email"
75+
data := struct {
76+
Success bool `json:"success"`
77+
KID string `json:"eab_kid"`
78+
HMAC string `json:"eab_hmac_key"`
79+
}{}
80+
81+
resp, err := http.PostForm(newAccountURL, url.Values{"email": {email}})
82+
if err != nil {
83+
return "", "", fmt.Errorf("acme: error creating ZeroSSL account EAB details request: %w", err)
84+
}
85+
defer resp.Body.Close()
86+
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
87+
return "", "", fmt.Errorf("acme: error reading ZeroSSL account EAB details response: %w", err)
88+
}
89+
90+
if !data.Success {
91+
return "", "", fmt.Errorf("acme: error in ZeroSSL account EAB details response, success=false")
92+
}
93+
return data.KID, data.HMAC, nil
94+
}
95+
96+
// RegisterWithZeroSSL Register the current account to the ZeroSSL server.
97+
func (r *Registrar) RegisterWithZeroSSL(options RegisterOptions) (*Resource, error) {
98+
if r.user.GetEmail() == "" {
99+
return nil, errors.New("acme: cannot register ZeroSSL account without email address")
100+
}
101+
102+
kid, hmac, err := createZeroSSLAccount(r.user.GetEmail())
103+
if err != nil {
104+
return nil, fmt.Errorf("acme: error registering new ZeroSSL account: %w", err)
105+
}
106+
107+
return r.RegisterWithExternalAccountBinding(RegisterEABOptions{
108+
TermsOfServiceAgreed: options.TermsOfServiceAgreed,
109+
Kid: kid,
110+
HmacEncoded: hmac,
111+
})
112+
}
113+
70114
// RegisterWithExternalAccountBinding Register the current account to the ACME server.
71115
func (r *Registrar) RegisterWithExternalAccountBinding(options RegisterEABOptions) (*Resource, error) {
72116
accMsg := acme.Account{

0 commit comments

Comments
 (0)