acmeapi: git.devever.net/hlandau/acmeapi Index | Files | Directories

package acmeapi

import "git.devever.net/hlandau/acmeapi"

Package acmeapi provides an API for accessing ACME servers.

See type RealmClient for introductory documentation.

Index

Package Files

api-res.go api.go nonce.go ocsp.go types.go util-errors.go util-retry.go

Constants

const (
    // The account is usable. This is the initial state.
    AccountValid AccountStatus = "valid"
    // The account is no longer usable, by accountholder request. This is a final
    // state. This is the only state which can be explicitly requested by the
    // client by setting it as the Status field.
    AccountDeactivated = "deactivated"
    // The account is no longer usable, due to administrative action.
    // This is a final state.
    AccountRevoked = "revoked"
)
const (
    // The order is waiting for one or more client actions before issuance
    // occurs. This is the initial state.
    OrderPending OrderStatus = "pending"
    // All preconditions to order fulfilment have been completed, and now the
    // order is simply waiting for a client to invoke the finalize operation. The
    // order will then transition to "processing".
    OrderReady = "ready"
    // Issuance is underway, and the state will transition to "valid" or
    // "invalid" automatically.
    OrderProcessing = "processing"
    // The order is valid. The certificate has been issued and can be retrieved.
    // This is a final state.
    OrderValid = "valid"
    // The certificate issuance request has failed.
    // This is a final state.
    OrderInvalid = "invalid"
)
const (
    // The authorization is waiting for one or more client actions before
    // it becomes valid. This is the initial state.
    AuthorizationPending AuthorizationStatus = "pending"
    // The authorization is valid.
    // The only state transition possible is to "revoked".
    AuthorizationValid = "valid"
    // The authorization is invalid.
    // This is a final state.
    AuthorizationInvalid = "invalid"
    // The authorization is deactivated.
    // This is a final state.
    AuthorizationDeactivated = "deactivated"
    // The authorization has been revoked.
    // This is a final state.
    AuthorizationRevoked = "revoked"
)
const (
    // The challenge is waiting to be initiated by client action before
    // verification occurs. This is the initial state.
    ChallengePending ChallengeStatus = "pending"
    // The challenge moves from the pending state to the processing state once
    // the client has initiated the challenge. The status will autonomously
    // advance to ChallengeValid or ChallengeInvalid.
    ChallengeProcessing = "processing"
    // Verification has succeeded. This is a final state.
    ChallengeValid = "valid"
    // Verification has failed. This is a final state.
    ChallengeInvalid = "invalid"
)

Variables

var ErrMissingEndpoints = errors.New("directory does not provide required endpoints")

Error returned if directory does not provide endpoints required by the specification.

var ErrUnknownDirectoryURL = errors.New("unable to retrieve directory because the directory URL is unknown")

Error returned when directory URL was needed for an operation but it is unknown.

var TestingAllowHTTP = false

Internal use only. All ACME URLs must use "https" and not "http". However, for testing purposes, if this is set, "http" URLs will be allowed. This is useful for testing when a test ACME server doesn't have TLS configured.

var UserAgent string

You should set this to a string identifying the code invoking this library. Optional.

You can alternatively set the user agent on a per-Client basis via Client.UserAgent, but usually a user agent is set at program scope and it makes more sense to set it here.

var _, Log = xlog.NewQuiet("acmeapi")

func ValidURL Uses

func ValidURL(u string) bool

Returns true if the URL given is (potentially) a valid ACME resource URL.

The URL must be an HTTPS URL.

type Account Uses

type Account struct {
    // The URL of the account.
    URL string `json:"-"`

    // Private key used to authorize requests. This is never sent to any server,
    // but is used to sign requests when passed as an argument to RealmClient
    // methods.
    PrivateKey crypto.PrivateKey `json:"-"`

    // Account public key.
    //
    // Always sent by the server; cannot be modified directly by client (use the
    // ChangeKey method).
    Key *jose.JSONWebKey `json:"key,omitempty"`

    // Account status.
    //
    // Always sent by server. Cannot be directly modified by client in general,
    // except that a client may set this to AccountDeactivated ("deactivated") to
    // request deactivation. This is the only client-initiated change to this
    // field allowed.
    Status AccountStatus `json:"status,omitempty"`

    // Contact URIs which may be used to contact the accountholder.
    //
    // Most realms will accept e. mail addresses expressed as “mailto:” URIs
    // here. Some realms may accept “tel:” URIs. Acceptance of other URIs is in
    // practice unlikely, and may result in rejection by the server.
    //
    // Always sent by the server, and may be sent by client to modify the current
    // value. If this field is not specified when registering, the account will
    // have no contact URIs, and if the field is not specified when updating the
    // account, the current set of contact URIs will be left unchanged.
    ContactURIs []string `json:"contact,omitempty"`

    // Whether the client agrees/has agreed to the terms of service.
    //
    // Always sent by the server, and may be sent by client to indicate assent.
    TermsOfServiceAgreed bool `json:"termsOfServiceAgreed,omitempty"`

    // URL at which the orders attached to the account can be enumerated.
    //
    // Always sent by server, if enumeration is supported. Read only.
    OrdersURL string `json:"orders,omitempty"`
}

Represents an account.

type AccountStatus Uses

type AccountStatus string

Specifies a current account status.

func (AccountStatus) IsFinal Uses

func (s AccountStatus) IsFinal() bool

Returns true iff the account status is a final status.

func (AccountStatus) IsWellFormed Uses

func (s AccountStatus) IsWellFormed() bool

Returns true iff the account status is a recognised account status value.

func (*AccountStatus) UnmarshalJSON Uses

func (s *AccountStatus) UnmarshalJSON(data []byte) error

Implements encoding/json.Unmarshaler.

type Authorization Uses

type Authorization struct {
    // The URL of the authorization.
    URL string `json:"-"`

    // The identifier for which authorization is required.
    //
    // Sent by server. Read only.
    Identifier Identifier `json:"identifier,omitempty"`

    // The status of the authorization.
    //
    // Sent by server. Read only.
    Status AuthorizationStatus `json:"status,omitempty"`

    // The expiry time of the authorization.
    //
    // May be sent by server; always sent if status is "valid". Read only.
    Expires time.Time `json:"expires,omitempty"`

    // True if the authorization is for a wildcard domain name.
    Wildcard bool `json:"wildcard,omitempty"`

    // Array of Challenge objects. Any one challenge in the array must be
    // completed to complete the authorization.
    //
    // Always sent by server. Read only.
    Challenges []Challenge `json:"challenges,omitempty"`
    // contains filtered or unexported fields
}

Represents an authorization which must be completed to enable certificate issuance.

type AuthorizationStatus Uses

type AuthorizationStatus string

Specifies an authorization status.

func (AuthorizationStatus) IsFinal Uses

func (s AuthorizationStatus) IsFinal() bool

Returns true iff the authorization status is a final status.

func (AuthorizationStatus) IsWellFormed Uses

func (s AuthorizationStatus) IsWellFormed() bool

Returns true iff the authorization status is a recognised authorization status value.

func (*AuthorizationStatus) UnmarshalJSON Uses

func (s *AuthorizationStatus) UnmarshalJSON(data []byte) error

Implements encoding/json.Unmarshaler.

type Certificate Uses

type Certificate struct {
    // The URL of the certificate resource.
    URL string `json:"-"`

    // The chain of certificates which a TLS server should send to a client in
    // order to facilitate client verification. A slice of DER-encoded
    // certificates. The first certificate is the end-entity certificate, the
    // second certificate if any is the issuing intermediate certificate, etc.
    //
    // Does not generally include the root certificate. If you need it (e.g.
    // because you are using DANE) you must append it yourself.
    CertificateChain [][]byte `json:"-"`
}

Represents a certificate which has been issued.

type Challenge Uses

type Challenge struct {
    // The URL of the challenge object.
    //
    // Always sent by server. Read only.
    URL string `json:"url,omitempty"`

    // The challenge type.
    //
    // Always sent by server. Read only.
    Type string `json:"type,omitempty"`

    // The challenge status. Always sent by the server.
    Status ChallengeStatus `json:"status,omitempty"`

    // The time at which the challenge was successfully validated. Optional
    // unless Status is ChallengeValid.
    Validated time.Time `json:"validated,omitempty"` // RFC 3339

    // Error that occurred while the server was validating the challenge, if any.
    // Multiple errors are indicated using subproblems. This should (but is not
    // guaranteed to) be present if Status is StatusInvalid.
    Error *Problem `json:"error,omitempty"`

    // Sent for http-01, tls-sni-02, dns-01.
    Token string `json:"token,omitempty"`
    // contains filtered or unexported fields
}

Represents a challenge which may be completed to satisfy an authorization requirement.

type ChallengeStatus Uses

type ChallengeStatus string

Specifies a challenge status.

func (ChallengeStatus) IsFinal Uses

func (s ChallengeStatus) IsFinal() bool

Returns true iff the challenge status is a final status.

func (ChallengeStatus) IsWellFormed Uses

func (s ChallengeStatus) IsWellFormed() bool

Returns true iff the challenge status is a recognised challenge status value.

func (*ChallengeStatus) UnmarshalJSON Uses

func (s *ChallengeStatus) UnmarshalJSON(data []byte) error

Implements encoding/json.Unmarshaler.

type HTTPError Uses

type HTTPError struct {
    // The HTTP response which was an error. Res.Body is no longer available
    // by the time the HTTPError is returned.
    Res *http.Response

    // If the response had an application/problem+json response body, this is
    // the parsed problem. nil if the problem document was unparseable.
    Problem *Problem

    // If the response had an application/problem+json response body, this is
    // that JSON data.
    ProblemRaw json.RawMessage
}

Error returned when an HTTP request results in a valid response, but which has an unexpected failure status code. Used so that the response can still be examined if desired.

func (*HTTPError) Error Uses

func (he *HTTPError) Error() string

Summarises the response status, headers, and the JSON problem body if available.

func (*HTTPError) Temporary Uses

func (he *HTTPError) Temporary() bool

type Identifier Uses

type Identifier struct {
    // The type of the identifier.
    Type IdentifierType `json:"type"`

    // The identifier string. The format is determined by Type.
    Value string `json:"value"`
}

Represents an identifier for a resource for which authorization is required.

func (*Identifier) String Uses

func (id *Identifier) String() string

type IdentifierType Uses

type IdentifierType string

A type of Identifier. Currently, the only supported value is "dns".

const (
    // Indicates that the identifier value is a DNS name.
    IdentifierTypeDNS IdentifierType = "dns"
)

type Order Uses

type Order struct {
    // The URL of the order.
    URL string `json:"-"`

    // Order status.
    //
    // Always sent by server; read-only.
    Status OrderStatus `json:"status,omitempty"`

    // Time at which the order expires.
    //
    // Sent by server if status is "pending" or "valid". Read only.
    Expires time.Time `json:"expires,omitempty"` // RFC 3339

    // The identifiers that the order pertains to.
    Identifiers []Identifier `json:"identifiers,omitempty"`

    // Optionally sent by client at order creation time to constrain certificate
    // validity period.
    //
    // Always sent by server and is immutable after resource creation.
    NotBefore time.Time `json:"notBefore,omitempty"` // RFC 3339
    NotAfter  time.Time `json:"notAfter,omitempty"`  // RFC 3339

    // An error which occurred during the processing of the order, if any.
    Error *Problem `json:"error,omitempty"` // RFC7807

    // List of URLs to authorization objects. All of the authorizations must be
    // completed to cause issuance. Issuance will commence as soon as all
    // authorizations are completed. Some authorizations may already be completed
    // when the order is created.
    //
    // Always sent by server. Read only.
    AuthorizationURLs []string `json:"authorizations,omitempty"`

    // An URL for submitting a CSR.
    FinalizeURL string `json:"finalize,omitempty"`

    // URL from which the certificate can be downloaded.
    //
    // Sent by server, but only when state is "valid". Read only.
    CertificateURL string `json:"certificate,omitempty"`
    // contains filtered or unexported fields
}

Represents a request for a certificate.

type OrderStatus Uses

type OrderStatus string

Specifies an order status.

func (OrderStatus) IsFinal Uses

func (s OrderStatus) IsFinal() bool

Returns true iff the order status is a final status.

func (OrderStatus) IsWellFormed Uses

func (s OrderStatus) IsWellFormed() bool

Returns true iff the order status is a recognised order status value.

func (*OrderStatus) UnmarshalJSON Uses

func (s *OrderStatus) UnmarshalJSON(data []byte) error

Implements encoding/json.Unmarshaler.

type Problem Uses

type Problem struct {
    // URI representing the problem type. Typically an URN.
    Type string `json:"type,omitempty"`
    // One-line summary of the error.
    Title string `json:"title,omitempty"`
    // HTTP status code (optional). If present, this should match the actual HTTP
    // status code returned. Advisory use only.
    Status int `json:"status,omitempty"`
    // More detailed explanation of the error.
    Detail string `json:"detail,omitempty"`
    // Optional, potentially relative URI identifying the specific problem.
    // May refer to an object which relates to the problem, etc.
    Instance string `json:"instance,omitempty"`

    // ACME-specific. Optional. List of problems which constitute components of
    // this problem.
    Subproblem []*Problem `json:"subproblems,omitempty"`

    // ACME-specific. Optional. Identifier relating to this problem.
    Identifier *Identifier `json:"identifier,omitempty"`
}

RFC7807 problem document. These structures are used by an ACME endpoint to return error information.

func (*Problem) Error Uses

func (p *Problem) Error() string

type RealmClient Uses

type RealmClient struct {
    // contains filtered or unexported fields
}

Client used to access and mutate resources provided by an ACME server.

REALM TERMINOLOGY

A “realm” means an ACME server, including all resources provided by it (e.g. accounts, orders, nonces). A nonce can be used to issue a signed request against a resource in a given realm if and only if it that nonce was issued by the same realm. (This term is specific to this client, and not a general ACME term. It is coined here to aid clarity in understanding the scope of ACME resources.)

You instantiate a RealmClient to consume the services of a realm. If you want to consume the services of multiple ACME servers — that is, multiple realms — you must create one RealmClient for each such realm. For example, if you wanted to use both the ExampleCA Live ACME server (which issues live certificates) and the ExampleCA Staging ACME server (which issues non-live certificates), you would need to create one RealmClient for each, and make any calls to the right RealmClient. Calling a method on the wrong RealmClient will fail under most circumstances.

INSTANTIATION

Call NewRealmClient to create a new RealmClient. When you create a RealmClient, you begin by passing the realm's (ACME server's) directory URL as part of the client configuration. This is the entrypoint for the consumption of the services provided by an ACME server realm. See RealmClientConfig for details.

DIRECTORY AUTO-DISCOVERY

It is possible to instantiate a RealmClient without passing a directory URL. If you do this, it is still possible to access some resources, where their particular URL is explicitly known. Moreover, a RealmClient which has no particular directory URL configured will automatically ascertain the appropriate directory URL when it (if ever) first loads a resource where the response from the server states the directory URL for the realm of which that resource is a member. Once this occurs, that RealmClient is thereafter specific to that realm, and must not be used for other purposes.

This directory auto-discovery mechanic is useful when you have an URL for a specific resource of an ACME realm but don't know the directory URL or the identity of the realm or any other information about the realm. This allows e.g. a certificate to be revoked knowing only its URL and private key. (The revocation endpoint is discoverable from the directory resource, which is itself discoverable by a link provided at the certificate resource, which is addressed via the certificate URL.)

CONCURRENCY

All methods of RealmClient are concurrency-safe. This means you can make multiple in-flight requests. This is useful, for example, when you create a new order and wish to retrieve all the authorizations created as part of it, which are referenced by URL and not serialized inline as part of the order object.

STANDARD METHOD ARGUMENTS

All methods which involve network I/O, or which may involve network I/O, take a context, to facilitate timeouts and cancellations.

All methods which involve making signed requests take an *Account argument. This is used to provide the URL and private key for the account; the other fields of *Account arguments are only used by methods which work directly with account resources.

The URL and PrivateKey fields of a provided *Account are mandatory in most cases. They are optional only in the following cases:

When calling UpsertAccount, the account URL may be omitted. (If the URL of an existing account is not known, this method may (and must) be used to discover the URL of the account before methods requiring an URL may be called.)

When calling Revoke, the account URL and account private key may be omitted, but only if the revocation request is being authorized on the basis of possession of the certificate's corresponding private key. All other revocation requests require an account URL and account private key.

func NewRealmClient Uses

func NewRealmClient(cfg RealmClientConfig) (*RealmClient, error)

Instantiates a new RealmClient.

func (*RealmClient) ChangeKey Uses

func (c *RealmClient) ChangeKey(ctx context.Context, acct *Account, newKey crypto.PrivateKey) error

Submit a key change request. The acct specified is used to authorize the change; the key for the account identified by acct.URL is changed from acct.PrivateKey/acct.Key to the key specified by newKey.

When this method returns nil error, the key has been successfully changed. The acct object's Key and PrivateKey fields will also be changed to newKey.

func (*RealmClient) CheckOCSP Uses

func (c *RealmClient) CheckOCSP(ctx context.Context, crt, issuer *x509.Certificate) (parsedResponse *ocsp.Response, rawResponse []byte, err error)

Checks OCSP for a certificate. The immediate issuer must be specified. If the certificate does not support OCSP, (nil, nil) is returned. Uses HTTP GET rather than POST. The response is verified. The caller must check the response status. The raw OCSP response is also returned, even if parsing failed and err is non-nil.

This method is realm-independent.

func (*RealmClient) Finalize Uses

func (c *RealmClient) Finalize(ctx context.Context, acct *Account, order *Order, csr []byte) error

Finalize the order. This will only work if the order has the "ready" status.

func (*RealmClient) GetMeta Uses

func (c *RealmClient) GetMeta(ctx context.Context) (RealmMeta, error)

Returns the directory metadata for the realm.

This method must be used to retrieve the realm's current Terms of Service URI when calling UpsertAccount.

func (*RealmClient) LoadAuthorization Uses

func (c *RealmClient) LoadAuthorization(ctx context.Context, acct *Account, az *Authorization) error

Load or reload the details of an authorization via its URI.

You can load an authorization from only the URI by creating an Authorization with the URI set and then calling this method.

func (*RealmClient) LoadCertificate Uses

func (c *RealmClient) LoadCertificate(ctx context.Context, cert *Certificate) error

func (*RealmClient) LoadOrder Uses

func (c *RealmClient) LoadOrder(ctx context.Context, order *Order) error

Load or reload an order.

You can load an order from its URI by creating an Order with the URI set and then calling this.

func (*RealmClient) LoadOrderOrCertificate Uses

func (c *RealmClient) LoadOrderOrCertificate(ctx context.Context, url string, order *Order, cert *Certificate) (isCertificate bool, err error)

This is a rather kludgy method needed for backwards compatibility with old-ACME URLs. If it is not known whether an URL is to a certificate or an order, this method can be used to load the URL. Returns with isCertificate == true if the URL appears to address a certificate (in which case the passed cert structure is populated), and isCertificate == false if the URL appears to address an order (in which case the passed order structure is populated). If the URL does not appear to address either type of resource, an error is returned.

func (*RealmClient) LocateAccount Uses

func (c *RealmClient) LocateAccount(ctx context.Context, acct *Account) error

Tries to find an existing account by key if the URL is not yet known. acct.URL must be empty. Fails if the account does not exist.

func (*RealmClient) NewAuthorization Uses

func (c *RealmClient) NewAuthorization(ctx context.Context, acct *Account, ident Identifier) (*Authorization, error)

Create a new authorization for the given hostname.

IDN hostnames must be in punycoded form.

Use of this method facilitates preauthentication, which is rarely necessary. Consider simply using NewOrder instead.

func (*RealmClient) NewOrder Uses

func (c *RealmClient) NewOrder(ctx context.Context, acct *Account, order *Order) error

Creates a new order. You must set at least the Identifiers field of Order. The NotBefore and NotAfter fields may also optionally be set. The other fields, including URI, will be filled in when the method returns.

func (*RealmClient) RegisterAccount Uses

func (c *RealmClient) RegisterAccount(ctx context.Context, acct *Account) error

Registers a new account. acct.URL must be empty and TermsOfServiceAgreed must be true.

The only fields of acct used for requests (that is, the only fields of an account modifiable by the client) are the ContactURIs field, the TermsOfServiceAgreed field and the Status field. The Status field is only sent if it is set to AccountDeactivated ("deactivated"); no other transition can be manually requested by the client.

func (*RealmClient) RespondToChallenge Uses

func (c *RealmClient) RespondToChallenge(ctx context.Context, acct *Account, ch *Challenge, response json.RawMessage) error

Submit a challenge response. Only the challenge URL is required to be set in the Challenge object. The account need only have the URL set.

func (*RealmClient) Revoke Uses

func (c *RealmClient) Revoke(ctx context.Context, acct *Account, certificateDER []byte, revocationKey crypto.PrivateKey, reason int) error

Requests revocation of a certificate. The certificate must be provided in DER form. If revocationKey is non-nil, the revocation request is signed with the given key; otherwise, the request is signed with the account key.

In general, you should expect to be able to revoke any certificate if a request to do so is signed using that certificate's key. You should also expect to be able to revoke a certificate if the request is signed with the account key of the account for which the certificate was issued, or where the request is signed with the account key of an account for which presently valid authorizations are held for all DNS names on the certificate.

The reason is a CRL reason code, or 0 if no explicit reason code is to be given.

func (*RealmClient) UpdateAccount Uses

func (c *RealmClient) UpdateAccount(ctx context.Context, acct *Account) error

Updates an existing account. acct.URL must be set.

func (*RealmClient) WaitForOrder Uses

func (c *RealmClient) WaitForOrder(ctx context.Context, order *Order) error

Wait for an order to finish processing. The order must be in the "processing" state and the method returns once this ceases to be the case. Only the URI is required to be set.

func (*RealmClient) WaitLoadAuthorization Uses

func (c *RealmClient) WaitLoadAuthorization(ctx context.Context, acct *Account, az *Authorization) error

Like LoadAuthorization, but waits the retry time if this is not the first attempt to load this authorization. To be used when polling.

The retry delay will not work if you recreate the object; use the same Authorization struct between calls.

func (*RealmClient) WaitLoadOrder Uses

func (c *RealmClient) WaitLoadOrder(ctx context.Context, order *Order) error

Like LoadOrder, but waits the retry time if this is not the first attempt to load this certificate. To be used when polling.

The retry delay will not work if you recreate the object; use the same Challenge struct between calls.

type RealmClientConfig Uses

type RealmClientConfig struct {
    // Optional but usually necessary. The Directory URL for the ACME realm (ACME
    // server). This must be an HTTPS URL. This will usually be provided via
    // out-of-band means; it is the root from which all other ACME resources are
    // accessed.
    //
    // Specifying the directory URL is usually necessary, but it can be omitted
    // in some cases; see the documentation for RealmClient.
    DirectoryURL string

    // Optional. HTTP client used to make HTTP requests. If this is nil, the
    // default net/http Client is used, which will suffice in the vast majority
    // of cases.
    HTTPClient *http.Client

    // Optional. Custom User-Agent string. If not specified, uses the global
    // User-Agent string configured at acmeapi package level (UserAgent var).
    UserAgent string
}

Configuration data used to instantiate a RealmClient.

type RealmMeta Uses

type RealmMeta struct {
    // (Sent by server; optional.) If the CA requires agreement to certain terms of
    // service, this is set to an URL for the terms of service document.
    TermsOfServiceURL string `json:"termsOfService,omitempty"`

    // (Sent by server; optional.) A website pertaining to the CA.
    WebsiteURL string `json:"website,omitempty"`

    // (Sent by server; optional.) List of domain names which the CA recognises as
    // referring to itself for the purposes of CAA record validation.
    CAAIdentities []string `json:"caaIdentities,omitempty"`

    // (Sent by server; optional.) As per specification.
    ExternalAccountRequired bool `json:"externalAccountRequired,omitempty"`
}

Metadata for a realm, retrieved from the directory resource.

Directories

PathSynopsis
acmeendpointsPackage acmeendpoints provides information on known ACME servers.
acmeutilsPackage acmeutils provides miscellaneous ACME-related utility functions.
pebbletestPackage pebbletest provides facilities for using Pebble during testing.

Package acmeapi imports 28 packages (graph). Updated 2018-09-04. Refresh now. Tools for package owners.