File: account.go

package info (click to toggle)
golang-github-smallstep-certificates 0.28.4-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,684 kB
  • sloc: sh: 367; makefile: 129
file content (135 lines) | stat: -rw-r--r-- 3,911 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package acme

import (
	"crypto"
	"encoding/base64"
	"encoding/json"
	"time"

	"go.step.sm/crypto/jose"

	"github.com/smallstep/certificates/authority/policy"
)

// Account is a subset of the internal account type containing only those
// attributes required for responses in the ACME protocol.
type Account struct {
	ID                     string           `json:"-"`
	Key                    *jose.JSONWebKey `json:"-"`
	Contact                []string         `json:"contact,omitempty"`
	Status                 Status           `json:"status"`
	OrdersURL              string           `json:"orders"`
	ExternalAccountBinding interface{}      `json:"externalAccountBinding,omitempty"`
	LocationPrefix         string           `json:"-"`
	ProvisionerID          string           `json:"-"`
	ProvisionerName        string           `json:"-"`
}

// GetLocation returns the URL location of the given account.
func (a *Account) GetLocation() string {
	if a.LocationPrefix == "" {
		return ""
	}
	return a.LocationPrefix + a.ID
}

// ToLog enables response logging.
func (a *Account) ToLog() (interface{}, error) {
	b, err := json.Marshal(a)
	if err != nil {
		return nil, WrapErrorISE(err, "error marshaling account for logging")
	}
	return string(b), nil
}

// IsValid returns true if the Account is valid.
func (a *Account) IsValid() bool {
	return a.Status == StatusValid
}

// KeyToID converts a JWK to a thumbprint.
func KeyToID(jwk *jose.JSONWebKey) (string, error) {
	kid, err := jwk.Thumbprint(crypto.SHA256)
	if err != nil {
		return "", WrapErrorISE(err, "error generating jwk thumbprint")
	}
	return base64.RawURLEncoding.EncodeToString(kid), nil
}

// PolicyNames contains ACME account level policy names
type PolicyNames struct {
	DNSNames []string `json:"dns"`
	IPRanges []string `json:"ips"`
}

// X509Policy contains ACME account level X.509 policy
type X509Policy struct {
	Allowed            PolicyNames `json:"allow"`
	Denied             PolicyNames `json:"deny"`
	AllowWildcardNames bool        `json:"allowWildcardNames"`
}

// Policy is an ACME Account level policy
type Policy struct {
	X509 X509Policy `json:"x509"`
}

func (p *Policy) GetAllowedNameOptions() *policy.X509NameOptions {
	if p == nil {
		return nil
	}
	return &policy.X509NameOptions{
		DNSDomains: p.X509.Allowed.DNSNames,
		IPRanges:   p.X509.Allowed.IPRanges,
	}
}

func (p *Policy) GetDeniedNameOptions() *policy.X509NameOptions {
	if p == nil {
		return nil
	}
	return &policy.X509NameOptions{
		DNSDomains: p.X509.Denied.DNSNames,
		IPRanges:   p.X509.Denied.IPRanges,
	}
}

// AreWildcardNamesAllowed returns if wildcard names
// like *.example.com are allowed to be signed.
// Defaults to false.
func (p *Policy) AreWildcardNamesAllowed() bool {
	if p == nil {
		return false
	}
	return p.X509.AllowWildcardNames
}

// ExternalAccountKey is an ACME External Account Binding key.
type ExternalAccountKey struct {
	ID            string    `json:"id"`
	ProvisionerID string    `json:"provisionerID"`
	Reference     string    `json:"reference"`
	AccountID     string    `json:"-"`
	HmacKey       []byte    `json:"-"`
	CreatedAt     time.Time `json:"createdAt"`
	BoundAt       time.Time `json:"boundAt,omitempty"`
	Policy        *Policy   `json:"policy,omitempty"`
}

// AlreadyBound returns whether this EAK is already bound to
// an ACME Account or not.
func (eak *ExternalAccountKey) AlreadyBound() bool {
	return !eak.BoundAt.IsZero()
}

// BindTo binds the EAK to an Account.
// It returns an error if it's already bound.
func (eak *ExternalAccountKey) BindTo(account *Account) error {
	if eak.AlreadyBound() {
		return NewError(ErrorUnauthorizedType, "external account binding key with id '%s' was already bound to account '%s' on %s", eak.ID, eak.AccountID, eak.BoundAt)
	}
	eak.AccountID = account.ID
	eak.BoundAt = time.Now()
	eak.HmacKey = []byte{} // clearing the key bytes; can only be used once
	return nil
}