|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- // 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 (
- "crypto"
- "crypto/x509"
- "errors"
- "fmt"
- "net/http"
- "strings"
- "time"
- )
-
- // ACME server response statuses used to describe Authorization and Challenge states.
- const (
- StatusUnknown = "unknown"
- StatusPending = "pending"
- StatusProcessing = "processing"
- StatusValid = "valid"
- StatusInvalid = "invalid"
- StatusRevoked = "revoked"
- )
-
- // 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, defined in Problem Details for HTTP APIs doc
- // http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
- type Error struct {
- // StatusCode is The HTTP status code generated by the origin server.
- StatusCode int
- // ProblemType is a URI reference that identifies the problem type,
- // typically in a "urn:acme:error:xxx" form.
- ProblemType string
- // Detail is a human-readable explanation specific to this occurrence of the problem.
- Detail string
- // Header is the original server error response headers.
- // It may be nil.
- Header http.Header
- }
-
- func (e *Error) Error() string {
- return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
- }
-
- // AuthorizationError indicates that an authorization for an identifier
- // did not succeed.
- // It contains all errors from Challenge items of the failed Authorization.
- type AuthorizationError struct {
- // URI uniquely identifies the failed Authorization.
- URI string
-
- // Identifier is an AuthzID.Value of the failed Authorization.
- Identifier string
-
- // Errors is a collection of non-nil error values of Challenge items
- // of the failed Authorization.
- Errors []error
- }
-
- func (a *AuthorizationError) Error() string {
- e := make([]string, len(a.Errors))
- for i, err := range a.Errors {
- e[i] = err.Error()
- }
- return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
- }
-
- // 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-05#section-5.6
- func RateLimit(err error) (time.Duration, bool) {
- e, ok := err.(*Error)
- if !ok {
- return 0, false
- }
- // Some CA implementations may return incorrect values.
- // Use case-insensitive comparison.
- if !strings.HasSuffix(strings.ToLower(e.ProblemType), ":ratelimited") {
- return 0, false
- }
- if e.Header == nil {
- return 0, true
- }
- return retryAfter(e.Header.Get("Retry-After")), true
- }
-
- // Account is a user account. It is associated with a private key.
- type Account struct {
- // URI is the account unique ID, which is also a URL used to retrieve
- // account data from the CA.
- URI string
-
- // Contact is a slice of contact info used during registration.
- Contact []string
-
- // The terms user has agreed to.
- // A value not matching CurrentTerms indicates that the user hasn't agreed
- // to the actual Terms of Service of the CA.
- AgreedTerms string
-
- // Actual terms of a CA.
- CurrentTerms string
-
- // Authz is the authorization URL used to initiate a new authz flow.
- Authz string
-
- // Authorizations is a URI from which a list of authorizations
- // granted to this account can be fetched via a GET request.
- Authorizations string
-
- // Certificates is a URI from which a list of certificates
- // issued for this account can be fetched via a GET request.
- Certificates string
- }
-
- // Directory is ACME server discovery data.
- type Directory struct {
- // RegURL is an account endpoint URL, allowing for creating new
- // and modifying existing accounts.
- RegURL string
-
- // AuthzURL is used to initiate Identifier Authorization flow.
- AuthzURL string
-
- // CertURL is a new certificate issuance endpoint URL.
- CertURL string
-
- // RevokeURL is used to initiate a certificate revocation flow.
- RevokeURL string
-
- // Term is a URI 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
- }
-
- // Challenge encodes a returned CA challenge.
- // Its Error field may be non-nil if the challenge is part of an Authorization
- // with StatusInvalid.
- type Challenge struct {
- // Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01".
- Type string
-
- // URI is where a challenge response can be posted to.
- URI string
-
- // Token is a random value that uniquely identifies the challenge.
- Token string
-
- // Status identifies the status of this challenge.
- Status string
-
- // Error indicates the reason for an authorization failure
- // when this challenge was used.
- // The type of a non-nil value is *Error.
- Error error
- }
-
- // Authorization encodes an authorization response.
- type Authorization struct {
- // URI uniquely identifies a authorization.
- URI string
-
- // Status identifies the status of an authorization.
- Status string
-
- // Identifier is what the account is authorized to represent.
- Identifier AuthzID
-
- // Challenges that the client needs to fulfill in order to prove possession
- // of the identifier (for pending authorizations).
- // For final authorizations, the challenges that were used.
- Challenges []*Challenge
-
- // A collection of sets of challenges, each of which would be sufficient
- // to prove possession of the identifier.
- // Clients must complete a set of challenges that covers at least one set.
- // Challenges are identified by their indices in the challenges array.
- // If this field is empty, the client needs to complete all challenges.
- Combinations [][]int
- }
-
- // 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".
- }
-
- // wireAuthz is ACME JSON representation of Authorization objects.
- type wireAuthz struct {
- Status string
- Challenges []wireChallenge
- Combinations [][]int
- Identifier struct {
- Type string
- Value string
- }
- }
-
- func (z *wireAuthz) authorization(uri string) *Authorization {
- a := &Authorization{
- URI: uri,
- Status: z.Status,
- Identifier: AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
- Combinations: z.Combinations, // shallow copy
- Challenges: make([]*Challenge, len(z.Challenges)),
- }
- for i, v := range z.Challenges {
- a.Challenges[i] = v.challenge()
- }
- return a
- }
-
- func (z *wireAuthz) error(uri string) *AuthorizationError {
- err := &AuthorizationError{
- URI: uri,
- Identifier: z.Identifier.Value,
- }
- for _, raw := range z.Challenges {
- if raw.Error != nil {
- err.Errors = append(err.Errors, raw.Error.error(nil))
- }
- }
- return err
- }
-
- // wireChallenge is ACME JSON challenge representation.
- type wireChallenge struct {
- URI string `json:"uri"`
- Type string
- Token string
- Status string
- Error *wireError
- }
-
- func (c *wireChallenge) challenge() *Challenge {
- v := &Challenge{
- URI: c.URI,
- Type: c.Type,
- Token: c.Token,
- Status: c.Status,
- }
- if v.Status == "" {
- v.Status = StatusPending
- }
- if c.Error != nil {
- v.Error = c.Error.error(nil)
- }
- 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
- }
-
- func (e *wireError) error(h http.Header) *Error {
- return &Error{
- StatusCode: e.Status,
- ProblemType: e.Type,
- Detail: e.Detail,
- Header: h,
- }
- }
-
- // CertOption is an optional argument type for the TLS ChallengeCert methods for
- // customizing a temporary certificate for TLS-based challenges.
- type CertOption interface {
- privateCertOpt()
- }
-
- // WithKey creates an option holding a private/public key pair.
- // The private part signs a certificate, and the public part represents the signee.
- func WithKey(key crypto.Signer) CertOption {
- return &certOptKey{key}
- }
-
- type certOptKey struct {
- key crypto.Signer
- }
-
- func (*certOptKey) privateCertOpt() {}
-
- // WithTemplate creates an option for specifying a certificate template.
- // See x509.CreateCertificate for template usage details.
- //
- // In TLS ChallengeCert methods, the template is also used as parent,
- // resulting in a self-signed certificate.
- // The DNSNames field of t is always overwritten for tls-sni challenge certs.
- func WithTemplate(t *x509.Certificate) CertOption {
- return (*certOptTemplate)(t)
- }
-
- type certOptTemplate x509.Certificate
-
- func (*certOptTemplate) privateCertOpt() {}
|