Skip to content

Commit 5352b09

Browse files
benburkertgopherbot
authored andcommittedApr 8, 2022
acme/autocert: support External Account Binding (EAB) tokens
Support External Account Binding (EAB) tokens to the Manager as defined in RFC 8555, Section 7.3.4. If the ExternalAccountBinding field is set on Manager, pass it into the acme Account during registration. Fixes golang/go#48809 Change-Id: I64c38b05ab577acbde9f526638cc8104d15ff055 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/354189 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Trust: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Filippo Valsorda <filippo@golang.org> Run-TryBot: Filippo Valsorda <filippo@golang.org> Auto-Submit: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org>
1 parent ae2d966 commit 5352b09

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed
 

‎acme/autocert/autocert.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ type Manager struct {
170170
// in the template's ExtraExtensions field as is.
171171
ExtraExtensions []pkix.Extension
172172

173+
// ExternalAccountBinding optionally represents an arbitrary binding to an
174+
// account of the CA to which the ACME server is tied.
175+
// See RFC 8555, Section 7.3.4 for more details.
176+
ExternalAccountBinding *acme.ExternalAccountBinding
177+
173178
clientMu sync.Mutex
174179
client *acme.Client // initialized by acmeClient method
175180

@@ -996,7 +1001,7 @@ func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) {
9961001
if m.Email != "" {
9971002
contact = []string{"mailto:" + m.Email}
9981003
}
999-
a := &acme.Account{Contact: contact}
1004+
a := &acme.Account{Contact: contact, ExternalAccountBinding: m.ExternalAccountBinding}
10001005
_, err := client.Register(ctx, a, m.Prompt)
10011006
if err == nil || isAccountAlreadyExist(err) {
10021007
m.client = client

‎acme/autocert/autocert_test.go

+13
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,19 @@ func TestGetCertificate(t *testing.T) {
394394
}
395395
},
396396
},
397+
{
398+
name: "provideExternalAuth",
399+
hello: clientHelloInfo("example.org", algECDSA),
400+
domain: "example.org",
401+
prepare: func(t *testing.T, man *Manager, s *acmetest.CAServer) {
402+
s.ExternalAccountRequired()
403+
404+
man.ExternalAccountBinding = &acme.ExternalAccountBinding{
405+
KID: "test-key",
406+
Key: make([]byte, 32),
407+
}
408+
},
409+
},
397410
}
398411
for _, tt := range tests {
399412
t.Run(tt.name, func(t *testing.T) {

‎acme/autocert/internal/acmetest/ca.go

+34
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ type CAServer struct {
4949
challengeTypes []string
5050
url string
5151
roots *x509.CertPool
52+
eabRequired bool
5253

5354
mu sync.Mutex
5455
certCount int // number of issued certs
@@ -152,6 +153,15 @@ func (ca *CAServer) Roots() *x509.CertPool {
152153
return ca.roots
153154
}
154155

156+
// ExternalAccountRequired makes an EAB JWS required for account registration.
157+
func (ca *CAServer) ExternalAccountRequired() *CAServer {
158+
if ca.url != "" {
159+
panic("ExternalAccountRequired must be called before Start")
160+
}
161+
ca.eabRequired = true
162+
return ca
163+
}
164+
155165
// Start starts serving requests. The server address becomes available in the
156166
// URL field.
157167
func (ca *CAServer) Start() *CAServer {
@@ -224,6 +234,12 @@ type discovery struct {
224234
NewAccount string `json:"newAccount"`
225235
NewOrder string `json:"newOrder"`
226236
NewAuthz string `json:"newAuthz"`
237+
238+
Meta discoveryMeta `json:"meta,omitempty"`
239+
}
240+
241+
type discoveryMeta struct {
242+
ExternalAccountRequired bool `json:"externalAccountRequired,omitempty"`
227243
}
228244

229245
type challenge struct {
@@ -264,6 +280,9 @@ func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
264280
NewNonce: ca.serverURL("/new-nonce"),
265281
NewAccount: ca.serverURL("/new-account"),
266282
NewOrder: ca.serverURL("/new-order"),
283+
Meta: discoveryMeta{
284+
ExternalAccountRequired: ca.eabRequired,
285+
},
267286
}
268287
if err := json.NewEncoder(w).Encode(resp); err != nil {
269288
panic(fmt.Sprintf("discovery response: %v", err))
@@ -283,6 +302,21 @@ func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
283302
return
284303
}
285304
ca.acctRegistered = true
305+
306+
var req struct {
307+
ExternalAccountBinding json.RawMessage
308+
}
309+
310+
if err := decodePayload(&req, r.Body); err != nil {
311+
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
312+
return
313+
}
314+
315+
if ca.eabRequired && len(req.ExternalAccountBinding) == 0 {
316+
ca.httpErrorf(w, http.StatusBadRequest, "registration failed: no JWS for EAB")
317+
return
318+
}
319+
286320
// TODO: Check the user account key against a ca.accountKeys?
287321
w.Header().Set("Location", ca.serverURL("/accounts/1"))
288322
w.WriteHeader(http.StatusCreated)

0 commit comments

Comments
 (0)
Please sign in to comment.