Skip to content

Commit 16c4ecd

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 dfa0a6d commit 16c4ecd

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
@@ -142,6 +142,10 @@ func register(ctx *cli.Context, client *lego.Client) (*registration.Resource, er
142142
log.Fatal("You did not accept the TOS. Unable to proceed.")
143143
}
144144

145+
if ctx.GlobalString("server") == lego.ZeroSSLDirectory {
146+
return client.Registration.RegisterWithZeroSSL(registration.RegisterOptions{TermsOfServiceAgreed: true})
147+
}
148+
145149
if ctx.GlobalBool("eab") {
146150
kid := ctx.GlobalString("kid")
147151
hmacEncoded := ctx.GlobalString("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.GlobalIsSet("eab") {
55+
if client.GetExternalAccountRequired() && !ctx.GlobalIsSet("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
@@ -31,6 +31,9 @@ const (
3131

3232
// LEDirectoryStaging URL to the Let's Encrypt staging.
3333
LEDirectoryStaging = "https://acme-staging-v02.api.letsencrypt.org/directory"
34+
35+
// ZeroSSLDirectory URL to the ZeroSSL production.
36+
ZeroSSLDirectory = "https://acme.zerossl.com/v2/DV90"
3437
)
3538

3639
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)