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