Skip to content

Commit d461918

Browse files
committed
Merge branch 'master' into context-authority
2 parents 2ea0c70 + 65090da commit d461918

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+16440
-677
lines changed

.github/PULL_REQUEST_TEMPLATE

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,20 @@
1-
### Description
2-
Please describe your pull request.
1+
<!---
2+
Please provide answers in the spaces below each prompt, where applicable.
3+
Not every PR requires responses for each prompt.
4+
Use your discretion.
5+
-->
6+
#### Name of feature:
7+
8+
#### Pain or issue this feature alleviates:
9+
10+
#### Why is this important to the project (if not answered above):
11+
12+
#### Is there documentation on how to use this feature? If so, where?
13+
14+
#### In what environments or workflows is this feature supported?
15+
16+
#### In what environments or workflows is this feature explicitly NOT supported (if any)?
17+
18+
#### Supporting links/other PRs/issues:
319

420
💔Thank you!

acme/account.go

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"time"
88

99
"go.step.sm/crypto/jose"
10+
11+
"github.com/smallstep/certificates/authority/policy"
1012
)
1113

1214
// Account is a subset of the internal account type containing only those
@@ -43,15 +45,63 @@ func KeyToID(jwk *jose.JSONWebKey) (string, error) {
4345
return base64.RawURLEncoding.EncodeToString(kid), nil
4446
}
4547

48+
// PolicyNames contains ACME account level policy names
49+
type PolicyNames struct {
50+
DNSNames []string `json:"dns"`
51+
IPRanges []string `json:"ips"`
52+
}
53+
54+
// X509Policy contains ACME account level X.509 policy
55+
type X509Policy struct {
56+
Allowed PolicyNames `json:"allow"`
57+
Denied PolicyNames `json:"deny"`
58+
AllowWildcardNames bool `json:"allowWildcardNames"`
59+
}
60+
61+
// Policy is an ACME Account level policy
62+
type Policy struct {
63+
X509 X509Policy `json:"x509"`
64+
}
65+
66+
func (p *Policy) GetAllowedNameOptions() *policy.X509NameOptions {
67+
if p == nil {
68+
return nil
69+
}
70+
return &policy.X509NameOptions{
71+
DNSDomains: p.X509.Allowed.DNSNames,
72+
IPRanges: p.X509.Allowed.IPRanges,
73+
}
74+
}
75+
func (p *Policy) GetDeniedNameOptions() *policy.X509NameOptions {
76+
if p == nil {
77+
return nil
78+
}
79+
return &policy.X509NameOptions{
80+
DNSDomains: p.X509.Denied.DNSNames,
81+
IPRanges: p.X509.Denied.IPRanges,
82+
}
83+
}
84+
85+
// AreWildcardNamesAllowed returns if wildcard names
86+
// like *.example.com are allowed to be signed.
87+
// Defaults to false.
88+
func (p *Policy) AreWildcardNamesAllowed() bool {
89+
if p == nil {
90+
return false
91+
}
92+
return p.X509.AllowWildcardNames
93+
}
94+
4695
// ExternalAccountKey is an ACME External Account Binding key.
4796
type ExternalAccountKey struct {
4897
ID string `json:"id"`
4998
ProvisionerID string `json:"provisionerID"`
5099
Reference string `json:"reference"`
51100
AccountID string `json:"-"`
52-
KeyBytes []byte `json:"-"`
101+
HmacKey []byte `json:"-"`
53102
CreatedAt time.Time `json:"createdAt"`
54103
BoundAt time.Time `json:"boundAt,omitempty"`
104+
Policy *Policy `json:"policy,omitempty"`
55105
}
56106

57107
// AlreadyBound returns whether this EAK is already bound to
@@ -68,6 +118,6 @@ func (eak *ExternalAccountKey) BindTo(account *Account) error {
68118
}
69119
eak.AccountID = account.ID
70120
eak.BoundAt = time.Now()
71-
eak.KeyBytes = []byte{} // clearing the key bytes; can only be used once
121+
eak.HmacKey = []byte{} // clearing the key bytes; can only be used once
72122
return nil
73123
}

acme/account_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import (
77
"time"
88

99
"github.com/pkg/errors"
10-
"github.com/smallstep/assert"
1110
"go.step.sm/crypto/jose"
11+
12+
"github.com/smallstep/assert"
1213
)
1314

1415
func TestKeyToID(t *testing.T) {
@@ -95,7 +96,7 @@ func TestExternalAccountKey_BindTo(t *testing.T) {
9596
ID: "eakID",
9697
ProvisionerID: "provID",
9798
Reference: "ref",
98-
KeyBytes: []byte{1, 3, 3, 7},
99+
HmacKey: []byte{1, 3, 3, 7},
99100
},
100101
acct: &Account{
101102
ID: "accountID",
@@ -108,7 +109,7 @@ func TestExternalAccountKey_BindTo(t *testing.T) {
108109
ID: "eakID",
109110
ProvisionerID: "provID",
110111
Reference: "ref",
111-
KeyBytes: []byte{1, 3, 3, 7},
112+
HmacKey: []byte{1, 3, 3, 7},
112113
AccountID: "someAccountID",
113114
BoundAt: boundAt,
114115
},
@@ -138,7 +139,7 @@ func TestExternalAccountKey_BindTo(t *testing.T) {
138139
assert.Equals(t, ae.Subproblems, tt.err.Subproblems)
139140
} else {
140141
assert.Equals(t, eak.AccountID, acct.ID)
141-
assert.Equals(t, eak.KeyBytes, []byte{})
142+
assert.Equals(t, eak.HmacKey, []byte{})
142143
assert.NotNil(t, eak.BoundAt)
143144
}
144145
})

acme/api/account.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,7 @@ func NewAccount(w http.ResponseWriter, r *http.Request) {
134134
}
135135

136136
if eak != nil { // means that we have a (valid) External Account Binding key that should be bound, updated and sent in the response
137-
err := eak.BindTo(acc)
138-
if err != nil {
137+
if err := eak.BindTo(acc); err != nil {
139138
render.Error(w, err)
140139
return
141140
}

acme/api/account_test.go

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ import (
1313

1414
"github.com/go-chi/chi"
1515
"github.com/pkg/errors"
16+
17+
"go.step.sm/crypto/jose"
18+
1619
"github.com/smallstep/assert"
1720
"github.com/smallstep/certificates/acme"
1821
"github.com/smallstep/certificates/authority/provisioner"
19-
"go.step.sm/crypto/jose"
2022
)
2123

2224
var (
@@ -29,6 +31,22 @@ var (
2931
}
3032
)
3133

34+
type fakeProvisioner struct{}
35+
36+
func (*fakeProvisioner) AuthorizeOrderIdentifier(ctx context.Context, identifier provisioner.ACMEIdentifier) error {
37+
return nil
38+
}
39+
40+
func (*fakeProvisioner) AuthorizeSign(ctx context.Context, token string) ([]provisioner.SignOption, error) {
41+
return nil, nil
42+
}
43+
44+
func (*fakeProvisioner) AuthorizeRevoke(ctx context.Context, token string) error { return nil }
45+
func (*fakeProvisioner) GetID() string { return "" }
46+
func (*fakeProvisioner) GetName() string { return "" }
47+
func (*fakeProvisioner) DefaultTLSCertDuration() time.Duration { return 0 }
48+
func (*fakeProvisioner) GetOptions() *provisioner.Options { return nil }
49+
3250
func newProv() acme.Provisioner {
3351
// Initialize provisioners
3452
p := &provisioner.ACME{
@@ -41,6 +59,19 @@ func newProv() acme.Provisioner {
4159
return p
4260
}
4361

62+
func newProvWithOptions(options *provisioner.Options) acme.Provisioner {
63+
// Initialize provisioners
64+
p := &provisioner.ACME{
65+
Type: "ACME",
66+
Name: "test@acme-<test>provisioner.com",
67+
Options: options,
68+
}
69+
if err := p.Init(provisioner.Config{Claims: globalProvisionerClaims}); err != nil {
70+
fmt.Printf("%v", err)
71+
}
72+
return p
73+
}
74+
4475
func newACMEProv(t *testing.T) *provisioner.ACME {
4576
p := newProv()
4677
a, ok := p.(*provisioner.ACME)
@@ -50,6 +81,15 @@ func newACMEProv(t *testing.T) *provisioner.ACME {
5081
return a
5182
}
5283

84+
func newACMEProvWithOptions(t *testing.T, options *provisioner.Options) *provisioner.ACME {
85+
p := newProvWithOptions(options)
86+
a, ok := p.(*provisioner.ACME)
87+
if !ok {
88+
t.Fatal("not a valid ACME provisioner")
89+
}
90+
return a
91+
}
92+
5393
func createEABJWS(jwk *jose.JSONWebKey, hmacKey []byte, keyID, u string) (*jose.JSONWebSignature, error) {
5494
signer, err := jose.NewSigner(
5595
jose.SigningKey{
@@ -507,16 +547,9 @@ func TestHandler_NewAccount(t *testing.T) {
507547
}
508548
b, err := json.Marshal(nar)
509549
assert.FatalError(t, err)
510-
scepProvisioner := &provisioner.SCEP{
511-
Type: "SCEP",
512-
Name: "test@scep-<test>provisioner.com",
513-
}
514-
if err := scepProvisioner.Init(provisioner.Config{Claims: globalProvisionerClaims}); err != nil {
515-
assert.FatalError(t, err)
516-
}
517550
ctx := context.WithValue(context.Background(), payloadContextKey, &payloadInfo{value: b})
518551
ctx = context.WithValue(ctx, jwkContextKey, jwk)
519-
ctx = acme.NewProvisionerContext(ctx, scepProvisioner)
552+
ctx = acme.NewProvisionerContext(ctx, &fakeProvisioner{})
520553
return test{
521554
db: &acme.MockDB{},
522555
ctx: ctx,
@@ -563,7 +596,7 @@ func TestHandler_NewAccount(t *testing.T) {
563596
ID: "eakID",
564597
ProvisionerID: provID,
565598
Reference: "testeak",
566-
KeyBytes: []byte{1, 3, 3, 7},
599+
HmacKey: []byte{1, 3, 3, 7},
567600
CreatedAt: time.Now(),
568601
}
569602
return test{
@@ -737,7 +770,7 @@ func TestHandler_NewAccount(t *testing.T) {
737770
ID: "eakID",
738771
ProvisionerID: provID,
739772
Reference: "testeak",
740-
KeyBytes: []byte{1, 3, 3, 7},
773+
HmacKey: []byte{1, 3, 3, 7},
741774
CreatedAt: time.Now(),
742775
}, nil
743776
},

acme/api/eab.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import (
44
"context"
55
"encoding/json"
66

7-
"github.com/smallstep/certificates/acme"
87
"go.step.sm/crypto/jose"
8+
9+
"github.com/smallstep/certificates/acme"
910
)
1011

1112
// ExternalAccountBinding represents the ACME externalAccountBinding JWS
@@ -56,11 +57,19 @@ func validateExternalAccountBinding(ctx context.Context, nar *NewAccountRequest)
5657
return nil, acme.WrapErrorISE(err, "error retrieving external account key")
5758
}
5859

60+
if externalAccountKey == nil {
61+
return nil, acme.NewError(acme.ErrorUnauthorizedType, "the field 'kid' references an unknown key")
62+
}
63+
64+
if len(externalAccountKey.HmacKey) == 0 {
65+
return nil, acme.NewError(acme.ErrorServerInternalType, "external account binding key with id '%s' does not have secret bytes", keyID)
66+
}
67+
5968
if externalAccountKey.AlreadyBound() {
6069
return nil, acme.NewError(acme.ErrorUnauthorizedType, "external account binding key with id '%s' was already bound to account '%s' on %s", keyID, externalAccountKey.AccountID, externalAccountKey.BoundAt)
6170
}
6271

63-
payload, err := eabJWS.Verify(externalAccountKey.KeyBytes)
72+
payload, err := eabJWS.Verify(externalAccountKey.HmacKey)
6473
if err != nil {
6574
return nil, acme.WrapErrorISE(err, "error verifying externalAccountBinding signature")
6675
}

0 commit comments

Comments
 (0)