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 // ExternalAccountBinding represents an arbitrary binding to an account of 204 // the CA which the ACME server is tied to. 205 // See https://tools.ietf.org/html/rfc8555#section-7.3.4 for more details. 206 ExternalAccountBinding *ExternalAccountBinding 207} 208 209// ExternalAccountBinding contains the data needed to form a request with 210// an external account binding. 211// See https://tools.ietf.org/html/rfc8555#section-7.3.4 for more details. 212type ExternalAccountBinding struct { 213 // KID is the Key ID of the symmetric MAC key that the CA provides to 214 // identify an external account from ACME. 215 KID string 216 217 // Key is the bytes of the symmetric key that the CA provides to identify 218 // the account. Key must correspond to the KID. 219 Key []byte 220} 221 222func (e *ExternalAccountBinding) String() string { 223 return fmt.Sprintf("&{KID: %q, Key: redacted}", e.KID) 224} 225 226// Directory is ACME server discovery data. 227// See https://tools.ietf.org/html/rfc8555#section-7.1.1 for more details. 228type Directory struct { 229 // NonceURL indicates an endpoint where to fetch fresh nonce values from. 230 NonceURL string 231 232 // RegURL is an account endpoint URL, allowing for creating new accounts. 233 // Pre-RFC 8555 CAs also allow modifying existing accounts at this URL. 234 RegURL string 235 236 // OrderURL is used to initiate the certificate issuance flow 237 // as described in RFC 8555. 238 OrderURL string 239 240 // AuthzURL is used to initiate identifier pre-authorization flow. 241 // Empty string indicates the flow is unsupported by the CA. 242 AuthzURL string 243 244 // CertURL is a new certificate issuance endpoint URL. 245 // It is non-RFC 8555 compliant and is obsoleted by OrderURL. 246 CertURL string 247 248 // RevokeURL is used to initiate a certificate revocation flow. 249 RevokeURL string 250 251 // KeyChangeURL allows to perform account key rollover flow. 252 KeyChangeURL string 253 254 // Term is a URI identifying the current terms of service. 255 Terms string 256 257 // Website is an HTTP or HTTPS URL locating a website 258 // providing more information about the ACME server. 259 Website string 260 261 // CAA consists of lowercase hostname elements, which the ACME server 262 // recognises as referring to itself for the purposes of CAA record validation 263 // as defined in RFC6844. 264 CAA []string 265 266 // ExternalAccountRequired indicates that the CA requires for all account-related 267 // requests to include external account binding information. 268 ExternalAccountRequired bool 269} 270 271// rfcCompliant reports whether the ACME server implements RFC 8555. 272// Note that some servers may have incomplete RFC implementation 273// even if the returned value is true. 274// If rfcCompliant reports false, the server most likely implements draft-02. 275func (d *Directory) rfcCompliant() bool { 276 return d.OrderURL != "" 277} 278 279// Order represents a client's request for a certificate. 280// It tracks the request flow progress through to issuance. 281type Order struct { 282 // URI uniquely identifies an order. 283 URI string 284 285 // Status represents the current status of the order. 286 // It indicates which action the client should take. 287 // 288 // Possible values are StatusPending, StatusReady, StatusProcessing, StatusValid and StatusInvalid. 289 // Pending means the CA does not believe that the client has fulfilled the requirements. 290 // Ready indicates that the client has fulfilled all the requirements and can submit a CSR 291 // to obtain a certificate. This is done with Client's CreateOrderCert. 292 // Processing means the certificate is being issued. 293 // Valid indicates the CA has issued the certificate. It can be downloaded 294 // from the Order's CertURL. This is done with Client's FetchCert. 295 // Invalid means the certificate will not be issued. Users should consider this order 296 // abandoned. 297 Status string 298 299 // Expires is the timestamp after which CA considers this order invalid. 300 Expires time.Time 301 302 // Identifiers contains all identifier objects which the order pertains to. 303 Identifiers []AuthzID 304 305 // NotBefore is the requested value of the notBefore field in the certificate. 306 NotBefore time.Time 307 308 // NotAfter is the requested value of the notAfter field in the certificate. 309 NotAfter time.Time 310 311 // AuthzURLs represents authorizations to complete before a certificate 312 // for identifiers specified in the order can be issued. 313 // It also contains unexpired authorizations that the client has completed 314 // in the past. 315 // 316 // Authorization objects can be fetched using Client's GetAuthorization method. 317 // 318 // The required authorizations are dictated by CA policies. 319 // There may not be a 1:1 relationship between the identifiers and required authorizations. 320 // Required authorizations can be identified by their StatusPending status. 321 // 322 // For orders in the StatusValid or StatusInvalid state these are the authorizations 323 // which were completed. 324 AuthzURLs []string 325 326 // FinalizeURL is the endpoint at which a CSR is submitted to obtain a certificate 327 // once all the authorizations are satisfied. 328 FinalizeURL string 329 330 // CertURL points to the certificate that has been issued in response to this order. 331 CertURL string 332 333 // The error that occurred while processing the order as received from a CA, if any. 334 Error *Error 335} 336 337// OrderOption allows customizing Client.AuthorizeOrder call. 338type OrderOption interface { 339 privateOrderOpt() 340} 341 342// WithOrderNotBefore sets order's NotBefore field. 343func WithOrderNotBefore(t time.Time) OrderOption { 344 return orderNotBeforeOpt(t) 345} 346 347// WithOrderNotAfter sets order's NotAfter field. 348func WithOrderNotAfter(t time.Time) OrderOption { 349 return orderNotAfterOpt(t) 350} 351 352type orderNotBeforeOpt time.Time 353 354func (orderNotBeforeOpt) privateOrderOpt() {} 355 356type orderNotAfterOpt time.Time 357 358func (orderNotAfterOpt) privateOrderOpt() {} 359 360// Authorization encodes an authorization response. 361type Authorization struct { 362 // URI uniquely identifies a authorization. 363 URI string 364 365 // Status is the current status of an authorization. 366 // Possible values are StatusPending, StatusValid, StatusInvalid, StatusDeactivated, 367 // StatusExpired and StatusRevoked. 368 Status string 369 370 // Identifier is what the account is authorized to represent. 371 Identifier AuthzID 372 373 // The timestamp after which the CA considers the authorization invalid. 374 Expires time.Time 375 376 // Wildcard is true for authorizations of a wildcard domain name. 377 Wildcard bool 378 379 // Challenges that the client needs to fulfill in order to prove possession 380 // of the identifier (for pending authorizations). 381 // For valid authorizations, the challenge that was validated. 382 // For invalid authorizations, the challenge that was attempted and failed. 383 // 384 // RFC 8555 compatible CAs require users to fuflfill only one of the challenges. 385 Challenges []*Challenge 386 387 // A collection of sets of challenges, each of which would be sufficient 388 // to prove possession of the identifier. 389 // Clients must complete a set of challenges that covers at least one set. 390 // Challenges are identified by their indices in the challenges array. 391 // If this field is empty, the client needs to complete all challenges. 392 // 393 // This field is unused in RFC 8555. 394 Combinations [][]int 395} 396 397// AuthzID is an identifier that an account is authorized to represent. 398type AuthzID struct { 399 Type string // The type of identifier, "dns" or "ip". 400 Value string // The identifier itself, e.g. "example.org". 401} 402 403// DomainIDs creates a slice of AuthzID with "dns" identifier type. 404func DomainIDs(names ...string) []AuthzID { 405 a := make([]AuthzID, len(names)) 406 for i, v := range names { 407 a[i] = AuthzID{Type: "dns", Value: v} 408 } 409 return a 410} 411 412// IPIDs creates a slice of AuthzID with "ip" identifier type. 413// Each element of addr is textual form of an address as defined 414// in RFC1123 Section 2.1 for IPv4 and in RFC5952 Section 4 for IPv6. 415func IPIDs(addr ...string) []AuthzID { 416 a := make([]AuthzID, len(addr)) 417 for i, v := range addr { 418 a[i] = AuthzID{Type: "ip", Value: v} 419 } 420 return a 421} 422 423// wireAuthzID is ACME JSON representation of authorization identifier objects. 424type wireAuthzID struct { 425 Type string `json:"type"` 426 Value string `json:"value"` 427} 428 429// wireAuthz is ACME JSON representation of Authorization objects. 430type wireAuthz struct { 431 Identifier wireAuthzID 432 Status string 433 Expires time.Time 434 Wildcard bool 435 Challenges []wireChallenge 436 Combinations [][]int 437 Error *wireError 438} 439 440func (z *wireAuthz) authorization(uri string) *Authorization { 441 a := &Authorization{ 442 URI: uri, 443 Status: z.Status, 444 Identifier: AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value}, 445 Expires: z.Expires, 446 Wildcard: z.Wildcard, 447 Challenges: make([]*Challenge, len(z.Challenges)), 448 Combinations: z.Combinations, // shallow copy 449 } 450 for i, v := range z.Challenges { 451 a.Challenges[i] = v.challenge() 452 } 453 return a 454} 455 456func (z *wireAuthz) error(uri string) *AuthorizationError { 457 err := &AuthorizationError{ 458 URI: uri, 459 Identifier: z.Identifier.Value, 460 } 461 462 if z.Error != nil { 463 err.Errors = append(err.Errors, z.Error.error(nil)) 464 } 465 466 for _, raw := range z.Challenges { 467 if raw.Error != nil { 468 err.Errors = append(err.Errors, raw.Error.error(nil)) 469 } 470 } 471 472 return err 473} 474 475// Challenge encodes a returned CA challenge. 476// Its Error field may be non-nil if the challenge is part of an Authorization 477// with StatusInvalid. 478type Challenge struct { 479 // Type is the challenge type, e.g. "http-01", "tls-alpn-01", "dns-01". 480 Type string 481 482 // URI is where a challenge response can be posted to. 483 URI string 484 485 // Token is a random value that uniquely identifies the challenge. 486 Token string 487 488 // Status identifies the status of this challenge. 489 // In RFC 8555, possible values are StatusPending, StatusProcessing, StatusValid, 490 // and StatusInvalid. 491 Status string 492 493 // Validated is the time at which the CA validated this challenge. 494 // Always zero value in pre-RFC 8555. 495 Validated time.Time 496 497 // Error indicates the reason for an authorization failure 498 // when this challenge was used. 499 // The type of a non-nil value is *Error. 500 Error error 501} 502 503// wireChallenge is ACME JSON challenge representation. 504type wireChallenge struct { 505 URL string `json:"url"` // RFC 506 URI string `json:"uri"` // pre-RFC 507 Type string 508 Token string 509 Status string 510 Validated time.Time 511 Error *wireError 512} 513 514func (c *wireChallenge) challenge() *Challenge { 515 v := &Challenge{ 516 URI: c.URL, 517 Type: c.Type, 518 Token: c.Token, 519 Status: c.Status, 520 } 521 if v.URI == "" { 522 v.URI = c.URI // c.URL was empty; use legacy 523 } 524 if v.Status == "" { 525 v.Status = StatusPending 526 } 527 if c.Error != nil { 528 v.Error = c.Error.error(nil) 529 } 530 return v 531} 532 533// wireError is a subset of fields of the Problem Details object 534// as described in https://tools.ietf.org/html/rfc7807#section-3.1. 535type wireError struct { 536 Status int 537 Type string 538 Detail string 539 Instance string 540} 541 542func (e *wireError) error(h http.Header) *Error { 543 return &Error{ 544 StatusCode: e.Status, 545 ProblemType: e.Type, 546 Detail: e.Detail, 547 Instance: e.Instance, 548 Header: h, 549 } 550} 551 552// CertOption is an optional argument type for the TLS ChallengeCert methods for 553// customizing a temporary certificate for TLS-based challenges. 554type CertOption interface { 555 privateCertOpt() 556} 557 558// WithKey creates an option holding a private/public key pair. 559// The private part signs a certificate, and the public part represents the signee. 560func WithKey(key crypto.Signer) CertOption { 561 return &certOptKey{key} 562} 563 564type certOptKey struct { 565 key crypto.Signer 566} 567 568func (*certOptKey) privateCertOpt() {} 569 570// WithTemplate creates an option for specifying a certificate template. 571// See x509.CreateCertificate for template usage details. 572// 573// In TLS ChallengeCert methods, the template is also used as parent, 574// resulting in a self-signed certificate. 575// The DNSNames field of t is always overwritten for tls-sni challenge certs. 576func WithTemplate(t *x509.Certificate) CertOption { 577 return (*certOptTemplate)(t) 578} 579 580type certOptTemplate x509.Certificate 581 582func (*certOptTemplate) privateCertOpt() {} 583