1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package acme
6
7import (
8	"crypto"
9	"crypto/x509"
10	"errors"
11	"fmt"
12	"net/http"
13	"strings"
14	"time"
15)
16
17// ACME status values of Account, Order, Authorization and Challenge objects.
18// See https://tools.ietf.org/html/rfc8555#section-7.1.6 for details.
19const (
20	StatusDeactivated = "deactivated"
21	StatusExpired     = "expired"
22	StatusInvalid     = "invalid"
23	StatusPending     = "pending"
24	StatusProcessing  = "processing"
25	StatusReady       = "ready"
26	StatusRevoked     = "revoked"
27	StatusUnknown     = "unknown"
28	StatusValid       = "valid"
29)
30
31// CRLReasonCode identifies the reason for a certificate revocation.
32type CRLReasonCode int
33
34// CRL reason codes as defined in RFC 5280.
35const (
36	CRLReasonUnspecified          CRLReasonCode = 0
37	CRLReasonKeyCompromise        CRLReasonCode = 1
38	CRLReasonCACompromise         CRLReasonCode = 2
39	CRLReasonAffiliationChanged   CRLReasonCode = 3
40	CRLReasonSuperseded           CRLReasonCode = 4
41	CRLReasonCessationOfOperation CRLReasonCode = 5
42	CRLReasonCertificateHold      CRLReasonCode = 6
43	CRLReasonRemoveFromCRL        CRLReasonCode = 8
44	CRLReasonPrivilegeWithdrawn   CRLReasonCode = 9
45	CRLReasonAACompromise         CRLReasonCode = 10
46)
47
48var (
49	// ErrUnsupportedKey is returned when an unsupported key type is encountered.
50	ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
51
52	// ErrAccountAlreadyExists indicates that the Client's key has already been registered
53	// with the CA. It is returned by Register method.
54	ErrAccountAlreadyExists = errors.New("acme: account already exists")
55
56	// ErrNoAccount indicates that the Client's key has not been registered with the CA.
57	ErrNoAccount = errors.New("acme: account does not exist")
58)
59
60// Error is an ACME error, defined in Problem Details for HTTP APIs doc
61// http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
62type Error struct {
63	// StatusCode is The HTTP status code generated by the origin server.
64	StatusCode int
65	// ProblemType is a URI reference that identifies the problem type,
66	// typically in a "urn:acme:error:xxx" form.
67	ProblemType string
68	// Detail is a human-readable explanation specific to this occurrence of the problem.
69	Detail string
70	// Instance indicates a URL that the client should direct a human user to visit
71	// in order for instructions on how to agree to the updated Terms of Service.
72	// In such an event CA sets StatusCode to 403, ProblemType to
73	// "urn:ietf:params:acme:error:userActionRequired" and a Link header with relation
74	// "terms-of-service" containing the latest TOS URL.
75	Instance string
76	// Header is the original server error response headers.
77	// It may be nil.
78	Header http.Header
79}
80
81func (e *Error) Error() string {
82	return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
83}
84
85// AuthorizationError indicates that an authorization for an identifier
86// did not succeed.
87// It contains all errors from Challenge items of the failed Authorization.
88type AuthorizationError struct {
89	// URI uniquely identifies the failed Authorization.
90	URI string
91
92	// Identifier is an AuthzID.Value of the failed Authorization.
93	Identifier string
94
95	// Errors is a collection of non-nil error values of Challenge items
96	// of the failed Authorization.
97	Errors []error
98}
99
100func (a *AuthorizationError) Error() string {
101	e := make([]string, len(a.Errors))
102	for i, err := range a.Errors {
103		e[i] = err.Error()
104	}
105
106	if a.Identifier != "" {
107		return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
108	}
109
110	return fmt.Sprintf("acme: authorization error: %s", strings.Join(e, "; "))
111}
112
113// OrderError is returned from Client's order related methods.
114// It indicates the order is unusable and the clients should start over with
115// AuthorizeOrder.
116//
117// The clients can still fetch the order object from CA using GetOrder
118// to inspect its state.
119type OrderError struct {
120	OrderURL string
121	Status   string
122}
123
124func (oe *OrderError) Error() string {
125	return fmt.Sprintf("acme: order %s status: %s", oe.OrderURL, oe.Status)
126}
127
128// RateLimit reports whether err represents a rate limit error and
129// any Retry-After duration returned by the server.
130//
131// See the following for more details on rate limiting:
132// https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-5.6
133func RateLimit(err error) (time.Duration, bool) {
134	e, ok := err.(*Error)
135	if !ok {
136		return 0, false
137	}
138	// Some CA implementations may return incorrect values.
139	// Use case-insensitive comparison.
140	if !strings.HasSuffix(strings.ToLower(e.ProblemType), ":ratelimited") {
141		return 0, false
142	}
143	if e.Header == nil {
144		return 0, true
145	}
146	return retryAfter(e.Header.Get("Retry-After")), true
147}
148
149// Account is a user account. It is associated with a private key.
150// Non-RFC 8555 fields are empty when interfacing with a compliant CA.
151type Account struct {
152	// URI is the account unique ID, which is also a URL used to retrieve
153	// account data from the CA.
154	// When interfacing with RFC 8555-compliant CAs, URI is the "kid" field
155	// value in JWS signed requests.
156	URI string
157
158	// Contact is a slice of contact info used during registration.
159	// See https://tools.ietf.org/html/rfc8555#section-7.3 for supported
160	// formats.
161	Contact []string
162
163	// Status indicates current account status as returned by the CA.
164	// Possible values are StatusValid, StatusDeactivated, and StatusRevoked.
165	Status string
166
167	// OrdersURL is a URL from which a list of orders submitted by this account
168	// can be fetched.
169	OrdersURL string
170
171	// The terms user has agreed to.
172	// A value not matching CurrentTerms indicates that the user hasn't agreed
173	// to the actual Terms of Service of the CA.
174	//
175	// It is non-RFC 8555 compliant. Package users can store the ToS they agree to
176	// during Client's Register call in the prompt callback function.
177	AgreedTerms string
178
179	// Actual terms of a CA.
180	//
181	// It is non-RFC 8555 compliant. Use Directory's Terms field.
182	// When a CA updates their terms and requires an account agreement,
183	// a URL at which instructions to do so is available in Error's Instance field.
184	CurrentTerms string
185
186	// Authz is the authorization URL used to initiate a new authz flow.
187	//
188	// It is non-RFC 8555 compliant. Use Directory's AuthzURL or OrderURL.
189	Authz string
190
191	// Authorizations is a URI from which a list of authorizations
192	// granted to this account can be fetched via a GET request.
193	//
194	// It is non-RFC 8555 compliant and is obsoleted by OrdersURL.
195	Authorizations string
196
197	// Certificates is a URI from which a list of certificates
198	// issued for this account can be fetched via a GET request.
199	//
200	// It is non-RFC 8555 compliant and is obsoleted by OrdersURL.
201	Certificates string
202}
203
204// Directory is ACME server discovery data.
205// See https://tools.ietf.org/html/rfc8555#section-7.1.1 for more details.
206type Directory struct {
207	// NonceURL indicates an endpoint where to fetch fresh nonce values from.
208	NonceURL string
209
210	// RegURL is an account endpoint URL, allowing for creating new accounts.
211	// Pre-RFC 8555 CAs also allow modifying existing accounts at this URL.
212	RegURL string
213
214	// OrderURL is used to initiate the certificate issuance flow
215	// as described in RFC 8555.
216	OrderURL string
217
218	// AuthzURL is used to initiate identifier pre-authorization flow.
219	// Empty string indicates the flow is unsupported by the CA.
220	AuthzURL string
221
222	// CertURL is a new certificate issuance endpoint URL.
223	// It is non-RFC 8555 compliant and is obsoleted by OrderURL.
224	CertURL string
225
226	// RevokeURL is used to initiate a certificate revocation flow.
227	RevokeURL string
228
229	// KeyChangeURL allows to perform account key rollover flow.
230	KeyChangeURL string
231
232	// Term is a URI identifying the current terms of service.
233	Terms string
234
235	// Website is an HTTP or HTTPS URL locating a website
236	// providing more information about the ACME server.
237	Website string
238
239	// CAA consists of lowercase hostname elements, which the ACME server
240	// recognises as referring to itself for the purposes of CAA record validation
241	// as defined in RFC6844.
242	CAA []string
243
244	// ExternalAccountRequired indicates that the CA requires for all account-related
245	// requests to include external account binding information.
246	ExternalAccountRequired bool
247}
248
249// rfcCompliant reports whether the ACME server implements RFC 8555.
250// Note that some servers may have incomplete RFC implementation
251// even if the returned value is true.
252// If rfcCompliant reports false, the server most likely implements draft-02.
253func (d *Directory) rfcCompliant() bool {
254	return d.OrderURL != ""
255}
256
257// Order represents a client's request for a certificate.
258// It tracks the request flow progress through to issuance.
259type Order struct {
260	// URI uniquely identifies an order.
261	URI string
262
263	// Status represents the current status of the order.
264	// It indicates which action the client should take.
265	//
266	// Possible values are StatusPending, StatusReady, StatusProcessing, StatusValid and StatusInvalid.
267	// Pending means the CA does not believe that the client has fulfilled the requirements.
268	// Ready indicates that the client has fulfilled all the requirements and can submit a CSR
269	// to obtain a certificate. This is done with Client's CreateOrderCert.
270	// Processing means the certificate is being issued.
271	// Valid indicates the CA has issued the certificate. It can be downloaded
272	// from the Order's CertURL. This is done with Client's FetchCert.
273	// Invalid means the certificate will not be issued. Users should consider this order
274	// abandoned.
275	Status string
276
277	// Expires is the timestamp after which CA considers this order invalid.
278	Expires time.Time
279
280	// Identifiers contains all identifier objects which the order pertains to.
281	Identifiers []AuthzID
282
283	// NotBefore is the requested value of the notBefore field in the certificate.
284	NotBefore time.Time
285
286	// NotAfter is the requested value of the notAfter field in the certificate.
287	NotAfter time.Time
288
289	// AuthzURLs represents authorizations to complete before a certificate
290	// for identifiers specified in the order can be issued.
291	// It also contains unexpired authorizations that the client has completed
292	// in the past.
293	//
294	// Authorization objects can be fetched using Client's GetAuthorization method.
295	//
296	// The required authorizations are dictated by CA policies.
297	// There may not be a 1:1 relationship between the identifiers and required authorizations.
298	// Required authorizations can be identified by their StatusPending status.
299	//
300	// For orders in the StatusValid or StatusInvalid state these are the authorizations
301	// which were completed.
302	AuthzURLs []string
303
304	// FinalizeURL is the endpoint at which a CSR is submitted to obtain a certificate
305	// once all the authorizations are satisfied.
306	FinalizeURL string
307
308	// CertURL points to the certificate that has been issued in response to this order.
309	CertURL string
310
311	// The error that occurred while processing the order as received from a CA, if any.
312	Error *Error
313}
314
315// OrderOption allows customizing Client.AuthorizeOrder call.
316type OrderOption interface {
317	privateOrderOpt()
318}
319
320// WithOrderNotBefore sets order's NotBefore field.
321func WithOrderNotBefore(t time.Time) OrderOption {
322	return orderNotBeforeOpt(t)
323}
324
325// WithOrderNotAfter sets order's NotAfter field.
326func WithOrderNotAfter(t time.Time) OrderOption {
327	return orderNotAfterOpt(t)
328}
329
330type orderNotBeforeOpt time.Time
331
332func (orderNotBeforeOpt) privateOrderOpt() {}
333
334type orderNotAfterOpt time.Time
335
336func (orderNotAfterOpt) privateOrderOpt() {}
337
338// Authorization encodes an authorization response.
339type Authorization struct {
340	// URI uniquely identifies a authorization.
341	URI string
342
343	// Status is the current status of an authorization.
344	// Possible values are StatusPending, StatusValid, StatusInvalid, StatusDeactivated,
345	// StatusExpired and StatusRevoked.
346	Status string
347
348	// Identifier is what the account is authorized to represent.
349	Identifier AuthzID
350
351	// The timestamp after which the CA considers the authorization invalid.
352	Expires time.Time
353
354	// Wildcard is true for authorizations of a wildcard domain name.
355	Wildcard bool
356
357	// Challenges that the client needs to fulfill in order to prove possession
358	// of the identifier (for pending authorizations).
359	// For valid authorizations, the challenge that was validated.
360	// For invalid authorizations, the challenge that was attempted and failed.
361	//
362	// RFC 8555 compatible CAs require users to fuflfill only one of the challenges.
363	Challenges []*Challenge
364
365	// A collection of sets of challenges, each of which would be sufficient
366	// to prove possession of the identifier.
367	// Clients must complete a set of challenges that covers at least one set.
368	// Challenges are identified by their indices in the challenges array.
369	// If this field is empty, the client needs to complete all challenges.
370	//
371	// This field is unused in RFC 8555.
372	Combinations [][]int
373}
374
375// AuthzID is an identifier that an account is authorized to represent.
376type AuthzID struct {
377	Type  string // The type of identifier, "dns" or "ip".
378	Value string // The identifier itself, e.g. "example.org".
379}
380
381// DomainIDs creates a slice of AuthzID with "dns" identifier type.
382func DomainIDs(names ...string) []AuthzID {
383	a := make([]AuthzID, len(names))
384	for i, v := range names {
385		a[i] = AuthzID{Type: "dns", Value: v}
386	}
387	return a
388}
389
390// IPIDs creates a slice of AuthzID with "ip" identifier type.
391// Each element of addr is textual form of an address as defined
392// in RFC1123 Section 2.1 for IPv4 and in RFC5952 Section 4 for IPv6.
393func IPIDs(addr ...string) []AuthzID {
394	a := make([]AuthzID, len(addr))
395	for i, v := range addr {
396		a[i] = AuthzID{Type: "ip", Value: v}
397	}
398	return a
399}
400
401// wireAuthzID is ACME JSON representation of authorization identifier objects.
402type wireAuthzID struct {
403	Type  string `json:"type"`
404	Value string `json:"value"`
405}
406
407// wireAuthz is ACME JSON representation of Authorization objects.
408type wireAuthz struct {
409	Identifier   wireAuthzID
410	Status       string
411	Expires      time.Time
412	Wildcard     bool
413	Challenges   []wireChallenge
414	Combinations [][]int
415	Error        *wireError
416}
417
418func (z *wireAuthz) authorization(uri string) *Authorization {
419	a := &Authorization{
420		URI:          uri,
421		Status:       z.Status,
422		Identifier:   AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
423		Expires:      z.Expires,
424		Wildcard:     z.Wildcard,
425		Challenges:   make([]*Challenge, len(z.Challenges)),
426		Combinations: z.Combinations, // shallow copy
427	}
428	for i, v := range z.Challenges {
429		a.Challenges[i] = v.challenge()
430	}
431	return a
432}
433
434func (z *wireAuthz) error(uri string) *AuthorizationError {
435	err := &AuthorizationError{
436		URI:        uri,
437		Identifier: z.Identifier.Value,
438	}
439
440	if z.Error != nil {
441		err.Errors = append(err.Errors, z.Error.error(nil))
442	}
443
444	for _, raw := range z.Challenges {
445		if raw.Error != nil {
446			err.Errors = append(err.Errors, raw.Error.error(nil))
447		}
448	}
449
450	return err
451}
452
453// Challenge encodes a returned CA challenge.
454// Its Error field may be non-nil if the challenge is part of an Authorization
455// with StatusInvalid.
456type Challenge struct {
457	// Type is the challenge type, e.g. "http-01", "tls-alpn-01", "dns-01".
458	Type string
459
460	// URI is where a challenge response can be posted to.
461	URI string
462
463	// Token is a random value that uniquely identifies the challenge.
464	Token string
465
466	// Status identifies the status of this challenge.
467	// In RFC 8555, possible values are StatusPending, StatusProcessing, StatusValid,
468	// and StatusInvalid.
469	Status string
470
471	// Validated is the time at which the CA validated this challenge.
472	// Always zero value in pre-RFC 8555.
473	Validated time.Time
474
475	// Error indicates the reason for an authorization failure
476	// when this challenge was used.
477	// The type of a non-nil value is *Error.
478	Error error
479}
480
481// wireChallenge is ACME JSON challenge representation.
482type wireChallenge struct {
483	URL       string `json:"url"` // RFC
484	URI       string `json:"uri"` // pre-RFC
485	Type      string
486	Token     string
487	Status    string
488	Validated time.Time
489	Error     *wireError
490}
491
492func (c *wireChallenge) challenge() *Challenge {
493	v := &Challenge{
494		URI:    c.URL,
495		Type:   c.Type,
496		Token:  c.Token,
497		Status: c.Status,
498	}
499	if v.URI == "" {
500		v.URI = c.URI // c.URL was empty; use legacy
501	}
502	if v.Status == "" {
503		v.Status = StatusPending
504	}
505	if c.Error != nil {
506		v.Error = c.Error.error(nil)
507	}
508	return v
509}
510
511// wireError is a subset of fields of the Problem Details object
512// as described in https://tools.ietf.org/html/rfc7807#section-3.1.
513type wireError struct {
514	Status   int
515	Type     string
516	Detail   string
517	Instance string
518}
519
520func (e *wireError) error(h http.Header) *Error {
521	return &Error{
522		StatusCode:  e.Status,
523		ProblemType: e.Type,
524		Detail:      e.Detail,
525		Instance:    e.Instance,
526		Header:      h,
527	}
528}
529
530// CertOption is an optional argument type for the TLS ChallengeCert methods for
531// customizing a temporary certificate for TLS-based challenges.
532type CertOption interface {
533	privateCertOpt()
534}
535
536// WithKey creates an option holding a private/public key pair.
537// The private part signs a certificate, and the public part represents the signee.
538func WithKey(key crypto.Signer) CertOption {
539	return &certOptKey{key}
540}
541
542type certOptKey struct {
543	key crypto.Signer
544}
545
546func (*certOptKey) privateCertOpt() {}
547
548// WithTemplate creates an option for specifying a certificate template.
549// See x509.CreateCertificate for template usage details.
550//
551// In TLS ChallengeCert methods, the template is also used as parent,
552// resulting in a self-signed certificate.
553// The DNSNames field of t is always overwritten for tls-sni challenge certs.
554func WithTemplate(t *x509.Certificate) CertOption {
555	return (*certOptTemplate)(t)
556}
557
558type certOptTemplate x509.Certificate
559
560func (*certOptTemplate) privateCertOpt() {}
561