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 server response statuses used to describe Authorization and Challenge states.
18const (
19	StatusUnknown    = "unknown"
20	StatusPending    = "pending"
21	StatusProcessing = "processing"
22	StatusValid      = "valid"
23	StatusInvalid    = "invalid"
24	StatusRevoked    = "revoked"
25)
26
27// CRLReasonCode identifies the reason for a certificate revocation.
28type CRLReasonCode int
29
30// CRL reason codes as defined in RFC 5280.
31const (
32	CRLReasonUnspecified          CRLReasonCode = 0
33	CRLReasonKeyCompromise        CRLReasonCode = 1
34	CRLReasonCACompromise         CRLReasonCode = 2
35	CRLReasonAffiliationChanged   CRLReasonCode = 3
36	CRLReasonSuperseded           CRLReasonCode = 4
37	CRLReasonCessationOfOperation CRLReasonCode = 5
38	CRLReasonCertificateHold      CRLReasonCode = 6
39	CRLReasonRemoveFromCRL        CRLReasonCode = 8
40	CRLReasonPrivilegeWithdrawn   CRLReasonCode = 9
41	CRLReasonAACompromise         CRLReasonCode = 10
42)
43
44// ErrUnsupportedKey is returned when an unsupported key type is encountered.
45var ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
46
47// Error is an ACME error, defined in Problem Details for HTTP APIs doc
48// http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
49type Error struct {
50	// StatusCode is The HTTP status code generated by the origin server.
51	StatusCode int
52	// ProblemType is a URI reference that identifies the problem type,
53	// typically in a "urn:acme:error:xxx" form.
54	ProblemType string
55	// Detail is a human-readable explanation specific to this occurrence of the problem.
56	Detail string
57	// Header is the original server error response headers.
58	// It may be nil.
59	Header http.Header
60}
61
62func (e *Error) Error() string {
63	return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
64}
65
66// AuthorizationError indicates that an authorization for an identifier
67// did not succeed.
68// It contains all errors from Challenge items of the failed Authorization.
69type AuthorizationError struct {
70	// URI uniquely identifies the failed Authorization.
71	URI string
72
73	// Identifier is an AuthzID.Value of the failed Authorization.
74	Identifier string
75
76	// Errors is a collection of non-nil error values of Challenge items
77	// of the failed Authorization.
78	Errors []error
79}
80
81func (a *AuthorizationError) Error() string {
82	e := make([]string, len(a.Errors))
83	for i, err := range a.Errors {
84		e[i] = err.Error()
85	}
86	return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
87}
88
89// RateLimit reports whether err represents a rate limit error and
90// any Retry-After duration returned by the server.
91//
92// See the following for more details on rate limiting:
93// https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-5.6
94func RateLimit(err error) (time.Duration, bool) {
95	e, ok := err.(*Error)
96	if !ok {
97		return 0, false
98	}
99	// Some CA implementations may return incorrect values.
100	// Use case-insensitive comparison.
101	if !strings.HasSuffix(strings.ToLower(e.ProblemType), ":ratelimited") {
102		return 0, false
103	}
104	if e.Header == nil {
105		return 0, true
106	}
107	return retryAfter(e.Header.Get("Retry-After"), 0), true
108}
109
110// Account is a user account. It is associated with a private key.
111type Account struct {
112	// URI is the account unique ID, which is also a URL used to retrieve
113	// account data from the CA.
114	URI string
115
116	// Contact is a slice of contact info used during registration.
117	Contact []string
118
119	// The terms user has agreed to.
120	// A value not matching CurrentTerms indicates that the user hasn't agreed
121	// to the actual Terms of Service of the CA.
122	AgreedTerms string
123
124	// Actual terms of a CA.
125	CurrentTerms string
126
127	// Authz is the authorization URL used to initiate a new authz flow.
128	Authz string
129
130	// Authorizations is a URI from which a list of authorizations
131	// granted to this account can be fetched via a GET request.
132	Authorizations string
133
134	// Certificates is a URI from which a list of certificates
135	// issued for this account can be fetched via a GET request.
136	Certificates string
137}
138
139// Directory is ACME server discovery data.
140type Directory struct {
141	// RegURL is an account endpoint URL, allowing for creating new
142	// and modifying existing accounts.
143	RegURL string
144
145	// AuthzURL is used to initiate Identifier Authorization flow.
146	AuthzURL string
147
148	// CertURL is a new certificate issuance endpoint URL.
149	CertURL string
150
151	// RevokeURL is used to initiate a certificate revocation flow.
152	RevokeURL string
153
154	// Term is a URI identifying the current terms of service.
155	Terms string
156
157	// Website is an HTTP or HTTPS URL locating a website
158	// providing more information about the ACME server.
159	Website string
160
161	// CAA consists of lowercase hostname elements, which the ACME server
162	// recognises as referring to itself for the purposes of CAA record validation
163	// as defined in RFC6844.
164	CAA []string
165}
166
167// Challenge encodes a returned CA challenge.
168// Its Error field may be non-nil if the challenge is part of an Authorization
169// with StatusInvalid.
170type Challenge struct {
171	// Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01".
172	Type string
173
174	// URI is where a challenge response can be posted to.
175	URI string
176
177	// Token is a random value that uniquely identifies the challenge.
178	Token string
179
180	// Status identifies the status of this challenge.
181	Status string
182
183	// Error indicates the reason for an authorization failure
184	// when this challenge was used.
185	// The type of a non-nil value is *Error.
186	Error error
187}
188
189// Authorization encodes an authorization response.
190type Authorization struct {
191	// URI uniquely identifies a authorization.
192	URI string
193
194	// Status identifies the status of an authorization.
195	Status string
196
197	// Identifier is what the account is authorized to represent.
198	Identifier AuthzID
199
200	// Challenges that the client needs to fulfill in order to prove possession
201	// of the identifier (for pending authorizations).
202	// For final authorizations, the challenges that were used.
203	Challenges []*Challenge
204
205	// A collection of sets of challenges, each of which would be sufficient
206	// to prove possession of the identifier.
207	// Clients must complete a set of challenges that covers at least one set.
208	// Challenges are identified by their indices in the challenges array.
209	// If this field is empty, the client needs to complete all challenges.
210	Combinations [][]int
211}
212
213// AuthzID is an identifier that an account is authorized to represent.
214type AuthzID struct {
215	Type  string // The type of identifier, e.g. "dns".
216	Value string // The identifier itself, e.g. "example.org".
217}
218
219// wireAuthz is ACME JSON representation of Authorization objects.
220type wireAuthz struct {
221	Status       string
222	Challenges   []wireChallenge
223	Combinations [][]int
224	Identifier   struct {
225		Type  string
226		Value string
227	}
228}
229
230func (z *wireAuthz) authorization(uri string) *Authorization {
231	a := &Authorization{
232		URI:          uri,
233		Status:       z.Status,
234		Identifier:   AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
235		Combinations: z.Combinations, // shallow copy
236		Challenges:   make([]*Challenge, len(z.Challenges)),
237	}
238	for i, v := range z.Challenges {
239		a.Challenges[i] = v.challenge()
240	}
241	return a
242}
243
244func (z *wireAuthz) error(uri string) *AuthorizationError {
245	err := &AuthorizationError{
246		URI:        uri,
247		Identifier: z.Identifier.Value,
248	}
249	for _, raw := range z.Challenges {
250		if raw.Error != nil {
251			err.Errors = append(err.Errors, raw.Error.error(nil))
252		}
253	}
254	return err
255}
256
257// wireChallenge is ACME JSON challenge representation.
258type wireChallenge struct {
259	URI    string `json:"uri"`
260	Type   string
261	Token  string
262	Status string
263	Error  *wireError
264}
265
266func (c *wireChallenge) challenge() *Challenge {
267	v := &Challenge{
268		URI:    c.URI,
269		Type:   c.Type,
270		Token:  c.Token,
271		Status: c.Status,
272	}
273	if v.Status == "" {
274		v.Status = StatusPending
275	}
276	if c.Error != nil {
277		v.Error = c.Error.error(nil)
278	}
279	return v
280}
281
282// wireError is a subset of fields of the Problem Details object
283// as described in https://tools.ietf.org/html/rfc7807#section-3.1.
284type wireError struct {
285	Status int
286	Type   string
287	Detail string
288}
289
290func (e *wireError) error(h http.Header) *Error {
291	return &Error{
292		StatusCode:  e.Status,
293		ProblemType: e.Type,
294		Detail:      e.Detail,
295		Header:      h,
296	}
297}
298
299// CertOption is an optional argument type for the TLSSNIxChallengeCert methods for
300// customizing a temporary certificate for TLS-SNI challenges.
301type CertOption interface {
302	privateCertOpt()
303}
304
305// WithKey creates an option holding a private/public key pair.
306// The private part signs a certificate, and the public part represents the signee.
307func WithKey(key crypto.Signer) CertOption {
308	return &certOptKey{key}
309}
310
311type certOptKey struct {
312	key crypto.Signer
313}
314
315func (*certOptKey) privateCertOpt() {}
316
317// WithTemplate creates an option for specifying a certificate template.
318// See x509.CreateCertificate for template usage details.
319//
320// In TLSSNIxChallengeCert methods, the template is also used as parent,
321// resulting in a self-signed certificate.
322// The DNSNames field of t is always overwritten for tls-sni challenge certs.
323func WithTemplate(t *x509.Certificate) CertOption {
324	return (*certOptTemplate)(t)
325}
326
327type certOptTemplate x509.Certificate
328
329func (*certOptTemplate) privateCertOpt() {}
330