-
Notifications
You must be signed in to change notification settings - Fork 2k
/
types.go
410 lines (339 loc) · 11.6 KB
/
types.go
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package acme
import (
"errors"
"fmt"
"net/http"
"time"
)
// ACME server response statuses used to describe Account, Authorization, and Challenge states.
const (
StatusUnknown = "unknown"
StatusPending = "pending"
StatusProcessing = "processing"
StatusValid = "valid"
StatusInvalid = "invalid"
StatusRevoked = "revoked"
StatusDeactivated = "deactivated"
StatusReady = "ready"
)
// CRLReasonCode identifies the reason for a certificate revocation.
type CRLReasonCode int
// CRL reason codes as defined in RFC 5280.
const (
CRLReasonUnspecified CRLReasonCode = 0
CRLReasonKeyCompromise CRLReasonCode = 1
CRLReasonCACompromise CRLReasonCode = 2
CRLReasonAffiliationChanged CRLReasonCode = 3
CRLReasonSuperseded CRLReasonCode = 4
CRLReasonCessationOfOperation CRLReasonCode = 5
CRLReasonCertificateHold CRLReasonCode = 6
CRLReasonRemoveFromCRL CRLReasonCode = 8
CRLReasonPrivilegeWithdrawn CRLReasonCode = 9
CRLReasonAACompromise CRLReasonCode = 10
)
// ErrUnsupportedKey is returned when an unsupported key type is encountered.
var ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
// Error is an ACME error as defined in RFC 7807, Problem Details for HTTP APIs.
type Error struct {
// StatusCode is The HTTP status code generated by the origin server.
StatusCode int
// Type is a URI that identifies the problem type, typically in
// a "urn:ietf:params:acme:error:xxx" form.
Type string
// Detail is a human-readable explanation specific to this occurrence of the problem.
Detail string
// Subproblems is an optional list of additional error information, usually
// indicating problems with specific identifiers during authorization.
Subproblems []Subproblem
// Header is the original server error response headers.
// It may be nil.
Header http.Header
}
func (e *Error) Error() string {
return fmt.Sprintf("acme: %s: %s", e.Type, e.Detail)
}
// An Subproblem is additional error detail that is included in an Error,
// usually indicating a problem with a specific identifier during authorization.
type Subproblem struct {
// Type is a URI that identifies the subproblem type, typically in
// "urn:ietf:params:acme:error:xxx" form.
Type string
// Detail is a human-readable explanation specific to this occurrence of the
// subproblem.
Detail string
// Identifier optionally indicates the identifier that this subproblem is about.
Identifier *AuthzID
}
// OrderInvalidError is returned when an order is marked as invalid.
type OrderInvalidError struct {
// Order is the order that is invalid.
Order *Order
}
func (e OrderInvalidError) Error() string {
if e.Order == nil || e.Order.Error == nil {
return "acme: order is invalid"
}
return fmt.Sprintf("acme: invalid order (%s): %s", e.Order.Error.Type, e.Order.Error.Detail)
}
// OrderPendingError is returned when an order is still pending after an
// attempted finalization.
type OrderPendingError struct {
// Order is the order that is pending.
Order *Order
}
func (e OrderPendingError) Error() string {
return "acme: order is pending due to incomplete authorization"
}
// AuthorizationError is returned when an authorization is marked as invalid.
type AuthorizationError struct {
// Authorization is the authorization that is invalid.
Authorization *Authorization
}
func (e AuthorizationError) Error() string {
if e.Authorization == nil {
return "acme: authorization is invalid"
}
return fmt.Sprintf("acme: authorization for identifier %s is %s", e.Authorization.Identifier.Value, e.Authorization.Status)
}
// RateLimit reports whether err represents a rate limit error and
// any Retry-After duration returned by the server.
//
// See the following for more details on rate limiting:
// https://tools.ietf.org/html/draft-ietf-acme-acme-09#section-6.5
func RateLimit(err error) (time.Time, bool) {
e, ok := err.(*Error)
if !ok || e.Type != "urn:ietf:params:acme:error:rateLimited" {
return time.Time{}, false
}
if e.Header == nil {
return time.Time{}, true
}
return retryAfter(e.Header.Get("Retry-After")), true
}
// Account is a user account. It is associated with a private key.
type Account struct {
// URL uniquely identifies the account.
URL string
// Status is the status of the account. Valid values are StatusValid,
// StatusDeactivated, and StatusRevoked.
Status string
// Contact is a list of URLs that the server can use to contact the client
// for issues related to this account.
Contact []string
// TermsAgreed indicates agreement with the terms of service. It is not
// modifiable after account creation.
TermsAgreed bool
// OrdersURL is the URL used to fetch a list of orders submitted by this
// account.
OrdersURL string
}
// Directory is ACME server discovery data.
type Directory struct {
// NewNonceURL is used to retrieve new nonces.
NewNonceURL string
// NewAccountURL is used to create new accounts.
NewAccountURL string
// NewOrderURL is used to create new orders.
NewOrderURL string
// NewAuthzURL is used to create new authorizations.
NewAuthzURL string
// RevokeCertURL is used to revoke a certificate.
RevokeCertURL string
// KeyChangeURL is used to change the account key.
KeyChangeURL string
// Terms is a URL identifying the current terms of service.
Terms string
// Website is an HTTP or HTTPS URL locating a website
// providing more information about the ACME server.
Website string
// CAA consists of lowercase hostname elements, which the ACME server
// recognises as referring to itself for the purposes of CAA record validation
// as defined in RFC6844.
CAA []string
// ExternalAccountRequired, if true, indicates that the CA requires that all
// new account requests include an ExternalAccountBinding field associating
// the new account with an external account.
ExternalAccountRequired bool
}
// NewOrder creates a new order with the domains provided, suitable for creating
// a TLS certificate order with CreateOrder.
func NewOrder(domains ...string) *Order {
o := &Order{Identifiers: make([]AuthzID, len(domains))}
for i, d := range domains {
o.Identifiers[i] = AuthzID{
Type: "dns",
Value: d,
}
}
return o
}
// An Order represents a request for a certificate and is used to track the
// progress through to issuance.
type Order struct {
// URL uniquely identifies the order.
URL string
// Status is the status of the order. It will be one of StatusPending,
// StatusReady, StatusProcessing, StatusValid, and StatusInvalid.
Status string
// Expires is the teimstamp after which the server will consider the order invalid.
Expires time.Time
// Identifiers is a list of identifiers that the order pertains to.
Identifiers []AuthzID
// NotBefore is an optional requested value of the notBefore field in the certificate.
NotBefore time.Time
// NotAfter is an optional requested value of the notAfter field in the certificate.
NotAfter time.Time
// Error is the error that occurred while processing the order, if any.
Error *Error
// Authorizations is a list of URLs for authorizations that the client needs
// to complete before the requested certificate can be issued. For
// valid/invalid orders, these are the authorizations that were completed.
Authorizations []string
// FinalizeURL is the URL that is used to finalize the Order.
FinalizeURL string
// CertificateURL is the URL for the certificate that has been issued in
// response to this order.
CertificateURL string
// RetryAfter is the timestamp, if any, to wait for before fetching this
// order again.
RetryAfter time.Time
}
// A Challenge is a CA challenge for an identifier.
type Challenge struct {
// Type is the challenge type, e.g. "http-01" or "dns-01".
Type string
// URL is the URL where a challenge response can be posted.
URL string
// Token is a random value that uniquely identifies the challenge.
Token string
// Validated is the time at which the server validated this challenge.
Validated time.Time
// Status identifies the status of this challenge. Valid values are
// StatusPending, StatusValid, and StatusInvalid.
Status string
// Error indicates the errors that occurred while the server was validating
// this challenge.
Error *Error
}
// Authorization encodes an authorization response.
type Authorization struct {
// URL uniquely identifies the authorization.
URL string
// Status is the status of the authorization. Valid values are
// StatusPending, StatusProcessing, StatusValid, StatusInvalid, and
// StatusRevoked.
Status string
// Identifier is the identifier that the account is authorized to represent.
Identifier AuthzID
// Wildcard is true if the authorization is for the base domain of a wildcard identifier.
Wildcard bool
// Expires is the timestamp after which the server will consider this authorization invalid.
Expires time.Time
// Challenges is the list of challenges that the client can fulfill in order
// to prove posession of the identifier. For valid/invalid authorizations,
// this is the list of challenges that were used.
Challenges []*Challenge
}
// AuthzID is an identifier that an account is authorized to represent.
type AuthzID struct {
Type string // The type of identifier, e.g. "dns".
Value string // The identifier itself, e.g. "example.org".
}
type wireAuthzID struct {
Type string `json:"type"`
Value string `json:"value"`
}
// wireAuthz is ACME JSON representation of Authorization objects.
type wireAuthz struct {
Status string
Challenges []wireChallenge
Expires time.Time
Identifier struct {
Type string
Value string
}
Wildcard bool
}
func (z *wireAuthz) authorization(url string) *Authorization {
a := &Authorization{
URL: url,
Status: z.Status,
Expires: z.Expires,
Identifier: AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
Wildcard: z.Wildcard,
Challenges: make([]*Challenge, len(z.Challenges)),
}
for i, v := range z.Challenges {
a.Challenges[i] = v.challenge()
}
return a
}
// wireChallenge is ACME JSON challenge representation.
type wireChallenge struct {
URL string
Type string
Token string
Status string
Validated time.Time
Error *Error
}
func (c *wireChallenge) challenge() *Challenge {
v := &Challenge{
URL: c.URL,
Type: c.Type,
Token: c.Token,
Status: c.Status,
Validated: c.Validated,
Error: c.Error,
}
if v.Status == "" {
v.Status = StatusUnknown
}
return v
}
// wireError is a subset of fields of the Problem Details object
// as described in https://tools.ietf.org/html/rfc7807#section-3.1.
type wireError struct {
Status int
Type string
Detail string
Subproblems []Subproblem
}
func (e *wireError) error(h http.Header) *Error {
return &Error{
StatusCode: e.Status,
Type: e.Type,
Detail: e.Detail,
Subproblems: e.Subproblems,
Header: h,
}
}
type wireOrder struct {
Status string
Expires time.Time
Identifiers []AuthzID
NotBefore time.Time
NotAfter time.Time
Error *Error
Authorizations []string
Finalize string
Certificate string
}
func (o *wireOrder) order(url string, retryHeader string) *Order {
return &Order{
URL: url,
Status: o.Status,
Expires: o.Expires,
Identifiers: o.Identifiers,
NotBefore: o.NotBefore,
NotAfter: o.NotAfter,
Error: o.Error,
Authorizations: o.Authorizations,
FinalizeURL: o.Finalize,
CertificateURL: o.Certificate,
RetryAfter: retryAfter(retryHeader),
}
}